]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Merge PR 'Use the text from modinfo.txt as the mod menu entry'
[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
195 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)"};
196 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)"};
197 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 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"};
199 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 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"};
203 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"};
204
205 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 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"};
208 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
210
211 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
213
214 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
216 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)"};
217 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
220
221 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
228 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"};
229 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"};
230 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"};
231
232 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"};
233
234 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"};
235
236 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
237
238 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
239
240 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)"};
241 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)"};
242 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
244
245 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 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"};
247
248 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."};
249
250 // FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting.
251 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)"};
252 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
253 {
254         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
255         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
256         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
257         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
258 };
259
260 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)"};
261 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)"};
262 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"};
263
264 extern cvar_t v_glslgamma_2d;
265
266 extern qbool v_flipped_state;
267
268 r_framebufferstate_t r_fb;
269
270 /// shadow volume bsp struct with automatically growing nodes buffer
271 svbsp_t r_svbsp;
272
273 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
274
275 rtexture_t *r_texture_blanknormalmap;
276 rtexture_t *r_texture_white;
277 rtexture_t *r_texture_grey128;
278 rtexture_t *r_texture_black;
279 rtexture_t *r_texture_notexture;
280 rtexture_t *r_texture_whitecube;
281 rtexture_t *r_texture_normalizationcube;
282 rtexture_t *r_texture_fogattenuation;
283 rtexture_t *r_texture_fogheighttexture;
284 rtexture_t *r_texture_gammaramps;
285 unsigned int r_texture_gammaramps_serial;
286 //rtexture_t *r_texture_fogintensity;
287 rtexture_t *r_texture_reflectcube;
288
289 // TODO: hash lookups?
290 typedef struct cubemapinfo_s
291 {
292         char basename[64];
293         rtexture_t *texture;
294 }
295 cubemapinfo_t;
296
297 int r_texture_numcubemaps;
298 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
299
300 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
301 unsigned int r_numqueries;
302 unsigned int r_maxqueries;
303
304 typedef struct r_qwskincache_s
305 {
306         char name[MAX_QPATH];
307         skinframe_t *skinframe;
308 }
309 r_qwskincache_t;
310
311 static r_qwskincache_t *r_qwskincache;
312 static int r_qwskincache_size;
313
314 /// vertex coordinates for a quad that covers the screen exactly
315 extern const float r_screenvertex3f[12];
316 const float r_screenvertex3f[12] =
317 {
318         0, 0, 0,
319         1, 0, 0,
320         1, 1, 0,
321         0, 1, 0
322 };
323
324 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
325 {
326         int i;
327         for (i = 0;i < verts;i++)
328         {
329                 out[0] = in[0] * r;
330                 out[1] = in[1] * g;
331                 out[2] = in[2] * b;
332                 out[3] = in[3];
333                 in += 4;
334                 out += 4;
335         }
336 }
337
338 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
339 {
340         int i;
341         for (i = 0;i < verts;i++)
342         {
343                 out[0] = r;
344                 out[1] = g;
345                 out[2] = b;
346                 out[3] = a;
347                 out += 4;
348         }
349 }
350
351 // FIXME: move this to client?
352 void FOG_clear(void)
353 {
354         if (gamemode == GAME_NEHAHRA)
355         {
356                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
357                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
358                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
359                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
360                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
361         }
362         r_refdef.fog_density = 0;
363         r_refdef.fog_red = 0;
364         r_refdef.fog_green = 0;
365         r_refdef.fog_blue = 0;
366         r_refdef.fog_alpha = 1;
367         r_refdef.fog_start = 0;
368         r_refdef.fog_end = 16384;
369         r_refdef.fog_height = 1<<30;
370         r_refdef.fog_fadedepth = 128;
371         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
372 }
373
374 static void R_BuildBlankTextures(void)
375 {
376         unsigned char data[4];
377         data[2] = 128; // normal X
378         data[1] = 128; // normal Y
379         data[0] = 255; // normal Z
380         data[3] = 255; // height
381         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
382         data[0] = 255;
383         data[1] = 255;
384         data[2] = 255;
385         data[3] = 255;
386         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
387         data[0] = 128;
388         data[1] = 128;
389         data[2] = 128;
390         data[3] = 255;
391         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
392         data[0] = 0;
393         data[1] = 0;
394         data[2] = 0;
395         data[3] = 255;
396         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
397 }
398
399 static void R_BuildNoTexture(void)
400 {
401         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
402 }
403
404 static void R_BuildWhiteCube(void)
405 {
406         unsigned char data[6*1*1*4];
407         memset(data, 255, sizeof(data));
408         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
409 }
410
411 static void R_BuildNormalizationCube(void)
412 {
413         int x, y, side;
414         vec3_t v;
415         vec_t s, t, intensity;
416 #define NORMSIZE 64
417         unsigned char *data;
418         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
419         for (side = 0;side < 6;side++)
420         {
421                 for (y = 0;y < NORMSIZE;y++)
422                 {
423                         for (x = 0;x < NORMSIZE;x++)
424                         {
425                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
426                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
427                                 switch(side)
428                                 {
429                                 default:
430                                 case 0:
431                                         v[0] = 1;
432                                         v[1] = -t;
433                                         v[2] = -s;
434                                         break;
435                                 case 1:
436                                         v[0] = -1;
437                                         v[1] = -t;
438                                         v[2] = s;
439                                         break;
440                                 case 2:
441                                         v[0] = s;
442                                         v[1] = 1;
443                                         v[2] = t;
444                                         break;
445                                 case 3:
446                                         v[0] = s;
447                                         v[1] = -1;
448                                         v[2] = -t;
449                                         break;
450                                 case 4:
451                                         v[0] = s;
452                                         v[1] = -t;
453                                         v[2] = 1;
454                                         break;
455                                 case 5:
456                                         v[0] = -s;
457                                         v[1] = -t;
458                                         v[2] = -1;
459                                         break;
460                                 }
461                                 intensity = 127.0f / sqrt(DotProduct(v, v));
462                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
463                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
464                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
465                                 data[((side*64+y)*64+x)*4+3] = 255;
466                         }
467                 }
468         }
469         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
470         Mem_Free(data);
471 }
472
473 static void R_BuildFogTexture(void)
474 {
475         int x, b;
476 #define FOGWIDTH 256
477         unsigned char data1[FOGWIDTH][4];
478         //unsigned char data2[FOGWIDTH][4];
479         double d, r, alpha;
480
481         r_refdef.fogmasktable_start = r_refdef.fog_start;
482         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
483         r_refdef.fogmasktable_range = r_refdef.fogrange;
484         r_refdef.fogmasktable_density = r_refdef.fog_density;
485
486         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
487         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
488         {
489                 d = (x * r - r_refdef.fogmasktable_start);
490                 if(developer_extra.integer)
491                         Con_DPrintf("%f ", d);
492                 d = max(0, d);
493                 if (r_fog_exp2.integer)
494                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
495                 else
496                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
497                 if(developer_extra.integer)
498                         Con_DPrintf(" : %f ", alpha);
499                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
500                 if(developer_extra.integer)
501                         Con_DPrintf(" = %f\n", alpha);
502                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
503         }
504
505         for (x = 0;x < FOGWIDTH;x++)
506         {
507                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
508                 data1[x][0] = b;
509                 data1[x][1] = b;
510                 data1[x][2] = b;
511                 data1[x][3] = 255;
512                 //data2[x][0] = 255 - b;
513                 //data2[x][1] = 255 - b;
514                 //data2[x][2] = 255 - b;
515                 //data2[x][3] = 255;
516         }
517         if (r_texture_fogattenuation)
518         {
519                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
520                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
521         }
522         else
523         {
524                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
525                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
526         }
527 }
528
529 static void R_BuildFogHeightTexture(void)
530 {
531         unsigned char *inpixels;
532         int size;
533         int x;
534         int y;
535         int j;
536         float c[4];
537         float f;
538         inpixels = NULL;
539         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
540         if (r_refdef.fogheighttexturename[0])
541                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
542         if (!inpixels)
543         {
544                 r_refdef.fog_height_tablesize = 0;
545                 if (r_texture_fogheighttexture)
546                         R_FreeTexture(r_texture_fogheighttexture);
547                 r_texture_fogheighttexture = NULL;
548                 if (r_refdef.fog_height_table2d)
549                         Mem_Free(r_refdef.fog_height_table2d);
550                 r_refdef.fog_height_table2d = NULL;
551                 if (r_refdef.fog_height_table1d)
552                         Mem_Free(r_refdef.fog_height_table1d);
553                 r_refdef.fog_height_table1d = NULL;
554                 return;
555         }
556         size = image_width;
557         r_refdef.fog_height_tablesize = size;
558         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
559         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
560         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
561         Mem_Free(inpixels);
562         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
563         // average fog color table accounting for every fog layer between a point
564         // and the camera.  (Note: attenuation is handled separately!)
565         for (y = 0;y < size;y++)
566         {
567                 for (x = 0;x < size;x++)
568                 {
569                         Vector4Clear(c);
570                         f = 0;
571                         if (x < y)
572                         {
573                                 for (j = x;j <= y;j++)
574                                 {
575                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
576                                         f++;
577                                 }
578                         }
579                         else
580                         {
581                                 for (j = x;j >= y;j--)
582                                 {
583                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
584                                         f++;
585                                 }
586                         }
587                         f = 1.0f / f;
588                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
589                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
590                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
591                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
592                 }
593         }
594         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
595 }
596
597 //=======================================================================================================================================================
598
599 static const char *builtinshaderstrings[] =
600 {
601 #include "shader_glsl.h"
602 0
603 };
604
605 //=======================================================================================================================================================
606
607 typedef struct shaderpermutationinfo_s
608 {
609         const char *pretext;
610         const char *name;
611 }
612 shaderpermutationinfo_t;
613
614 typedef struct shadermodeinfo_s
615 {
616         const char *sourcebasename;
617         const char *extension;
618         const char **builtinshaderstrings;
619         const char *pretext;
620         const char *name;
621         char *filename;
622         char *builtinstring;
623         int builtincrc;
624 }
625 shadermodeinfo_t;
626
627 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
628 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
629 {
630         {"#define USEDIFFUSE\n", " diffuse"},
631         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
632         {"#define USEVIEWTINT\n", " viewtint"},
633         {"#define USECOLORMAPPING\n", " colormapping"},
634         {"#define USESATURATION\n", " saturation"},
635         {"#define USEFOGINSIDE\n", " foginside"},
636         {"#define USEFOGOUTSIDE\n", " fogoutside"},
637         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
638         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
639         {"#define USEGAMMARAMPS\n", " gammaramps"},
640         {"#define USECUBEFILTER\n", " cubefilter"},
641         {"#define USEGLOW\n", " glow"},
642         {"#define USEBLOOM\n", " bloom"},
643         {"#define USESPECULAR\n", " specular"},
644         {"#define USEPOSTPROCESSING\n", " postprocessing"},
645         {"#define USEREFLECTION\n", " reflection"},
646         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
647         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
648         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
649         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
650         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
651         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
652         {"#define USEALPHAKILL\n", " alphakill"},
653         {"#define USEREFLECTCUBE\n", " reflectcube"},
654         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
655         {"#define USEBOUNCEGRID\n", " bouncegrid"},
656         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
657         {"#define USETRIPPY\n", " trippy"},
658         {"#define USEDEPTHRGB\n", " depthrgb"},
659         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
660         {"#define USESKELETAL\n", " skeletal"},
661         {"#define USEOCCLUDE\n", " occlude"}
662 };
663
664 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
665 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
666 {
667         // SHADERLANGUAGE_GLSL
668         {
669                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
683                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
684                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
685                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
686         },
687 };
688
689 struct r_glsl_permutation_s;
690 typedef struct r_glsl_permutation_s
691 {
692         /// hash lookup data
693         struct r_glsl_permutation_s *hashnext;
694         unsigned int mode;
695         uint64_t permutation;
696
697         /// indicates if we have tried compiling this permutation already
698         qbool compiled;
699         /// 0 if compilation failed
700         int program;
701         // texture units assigned to each detected uniform
702         int tex_Texture_First;
703         int tex_Texture_Second;
704         int tex_Texture_GammaRamps;
705         int tex_Texture_Normal;
706         int tex_Texture_Color;
707         int tex_Texture_Gloss;
708         int tex_Texture_Glow;
709         int tex_Texture_SecondaryNormal;
710         int tex_Texture_SecondaryColor;
711         int tex_Texture_SecondaryGloss;
712         int tex_Texture_SecondaryGlow;
713         int tex_Texture_Pants;
714         int tex_Texture_Shirt;
715         int tex_Texture_FogHeightTexture;
716         int tex_Texture_FogMask;
717         int tex_Texture_LightGrid;
718         int tex_Texture_Lightmap;
719         int tex_Texture_Deluxemap;
720         int tex_Texture_Attenuation;
721         int tex_Texture_Cube;
722         int tex_Texture_Refraction;
723         int tex_Texture_Reflection;
724         int tex_Texture_ShadowMap2D;
725         int tex_Texture_CubeProjection;
726         int tex_Texture_ScreenNormalMap;
727         int tex_Texture_ScreenDiffuse;
728         int tex_Texture_ScreenSpecular;
729         int tex_Texture_ReflectMask;
730         int tex_Texture_ReflectCube;
731         int tex_Texture_BounceGrid;
732         /// locations of detected uniforms in program object, or -1 if not found
733         int loc_Texture_First;
734         int loc_Texture_Second;
735         int loc_Texture_GammaRamps;
736         int loc_Texture_Normal;
737         int loc_Texture_Color;
738         int loc_Texture_Gloss;
739         int loc_Texture_Glow;
740         int loc_Texture_SecondaryNormal;
741         int loc_Texture_SecondaryColor;
742         int loc_Texture_SecondaryGloss;
743         int loc_Texture_SecondaryGlow;
744         int loc_Texture_Pants;
745         int loc_Texture_Shirt;
746         int loc_Texture_FogHeightTexture;
747         int loc_Texture_FogMask;
748         int loc_Texture_LightGrid;
749         int loc_Texture_Lightmap;
750         int loc_Texture_Deluxemap;
751         int loc_Texture_Attenuation;
752         int loc_Texture_Cube;
753         int loc_Texture_Refraction;
754         int loc_Texture_Reflection;
755         int loc_Texture_ShadowMap2D;
756         int loc_Texture_CubeProjection;
757         int loc_Texture_ScreenNormalMap;
758         int loc_Texture_ScreenDiffuse;
759         int loc_Texture_ScreenSpecular;
760         int loc_Texture_ReflectMask;
761         int loc_Texture_ReflectCube;
762         int loc_Texture_BounceGrid;
763         int loc_Alpha;
764         int loc_BloomBlur_Parameters;
765         int loc_ClientTime;
766         int loc_Color_Ambient;
767         int loc_Color_Diffuse;
768         int loc_Color_Specular;
769         int loc_Color_Glow;
770         int loc_Color_Pants;
771         int loc_Color_Shirt;
772         int loc_DeferredColor_Ambient;
773         int loc_DeferredColor_Diffuse;
774         int loc_DeferredColor_Specular;
775         int loc_DeferredMod_Diffuse;
776         int loc_DeferredMod_Specular;
777         int loc_DistortScaleRefractReflect;
778         int loc_EyePosition;
779         int loc_FogColor;
780         int loc_FogHeightFade;
781         int loc_FogPlane;
782         int loc_FogPlaneViewDist;
783         int loc_FogRangeRecip;
784         int loc_LightColor;
785         int loc_LightDir;
786         int loc_LightGridMatrix;
787         int loc_LightGridNormalMatrix;
788         int loc_LightPosition;
789         int loc_OffsetMapping_ScaleSteps;
790         int loc_OffsetMapping_LodDistance;
791         int loc_OffsetMapping_Bias;
792         int loc_PixelSize;
793         int loc_ReflectColor;
794         int loc_ReflectFactor;
795         int loc_ReflectOffset;
796         int loc_RefractColor;
797         int loc_Saturation;
798         int loc_ScreenCenterRefractReflect;
799         int loc_ScreenScaleRefractReflect;
800         int loc_ScreenToDepth;
801         int loc_ShadowMap_Parameters;
802         int loc_ShadowMap_TextureScale;
803         int loc_SpecularPower;
804         int loc_Skeletal_Transform12;
805         int loc_UserVec1;
806         int loc_UserVec2;
807         int loc_UserVec3;
808         int loc_UserVec4;
809         int loc_ColorFringe;
810         int loc_ViewTintColor;
811         int loc_ViewToLight;
812         int loc_ModelToLight;
813         int loc_TexMatrix;
814         int loc_BackgroundTexMatrix;
815         int loc_ModelViewProjectionMatrix;
816         int loc_ModelViewMatrix;
817         int loc_PixelToScreenTexCoord;
818         int loc_ModelToReflectCube;
819         int loc_ShadowMapMatrix;
820         int loc_BloomColorSubtract;
821         int loc_NormalmapScrollBlend;
822         int loc_BounceGridMatrix;
823         int loc_BounceGridIntensity;
824         /// uniform block bindings
825         int ubibind_Skeletal_Transform12_UniformBlock;
826         /// uniform block indices
827         int ubiloc_Skeletal_Transform12_UniformBlock;
828 }
829 r_glsl_permutation_t;
830
831 #define SHADERPERMUTATION_HASHSIZE 256
832
833
834 // non-degradable "lightweight" shader parameters to keep the permutations simpler
835 // these can NOT degrade! only use for simple stuff
836 enum
837 {
838         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
839         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
840         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
841         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
842         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
843         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
844         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
845         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
846         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
847         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
848         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
849         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
850         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
851         SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
852         SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
853 };
854 #define SHADERSTATICPARMS_COUNT 15
855
856 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
857 static int shaderstaticparms_count = 0;
858
859 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
860 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
861
862 extern qbool r_shadow_shadowmapsampler;
863 extern int r_shadow_shadowmappcf;
864 qbool R_CompileShader_CheckStaticParms(void)
865 {
866         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
867         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
868         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
869
870         // detect all
871         if (r_glsl_saturation_redcompensate.integer)
872                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
873         if (r_glsl_vertextextureblend_usebothalphas.integer)
874                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
875         if (r_shadow_glossexact.integer)
876                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
877         if (r_glsl_postprocess.integer)
878         {
879                 if (r_glsl_postprocess_uservec1_enable.integer)
880                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
881                 if (r_glsl_postprocess_uservec2_enable.integer)
882                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
883                 if (r_glsl_postprocess_uservec3_enable.integer)
884                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
885                 if (r_glsl_postprocess_uservec4_enable.integer)
886                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
887         }
888         if (r_fxaa.integer)
889                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
890         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
891                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
892
893         if (r_shadow_shadowmapsampler)
894                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
895         if (r_shadow_shadowmappcf > 1)
896                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
897         else if (r_shadow_shadowmappcf)
898                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
899         if (r_celshading.integer)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
901         if (r_celoutlines.integer)
902                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
903         if (r_colorfringe.value)
904                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
905
906         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
907 }
908
909 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
910         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
911                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
912         else \
913                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
914 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
915 {
916         shaderstaticparms_count = 0;
917
918         // emit all
919         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
934 }
935
936 /// information about each possible shader permutation
937 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
938 /// currently selected permutation
939 r_glsl_permutation_t *r_glsl_permutation;
940 /// storage for permutations linked in the hash table
941 memexpandablearray_t r_glsl_permutationarray;
942
943 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
944 {
945         //unsigned int hashdepth = 0;
946         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
947         r_glsl_permutation_t *p;
948         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
949         {
950                 if (p->mode == mode && p->permutation == permutation)
951                 {
952                         //if (hashdepth > 10)
953                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
954                         return p;
955                 }
956                 //hashdepth++;
957         }
958         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
959         p->mode = mode;
960         p->permutation = permutation;
961         p->hashnext = r_glsl_permutationhash[mode][hashindex];
962         r_glsl_permutationhash[mode][hashindex] = p;
963         //if (hashdepth > 10)
964         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
965         return p;
966 }
967
968 static char *R_ShaderStrCat(const char **strings)
969 {
970         char *string, *s;
971         const char **p = strings;
972         const char *t;
973         size_t len = 0;
974         for (p = strings;(t = *p);p++)
975                 len += strlen(t);
976         len++;
977         s = string = (char *)Mem_Alloc(r_main_mempool, len);
978         len = 0;
979         for (p = strings;(t = *p);p++)
980         {
981                 len = strlen(t);
982                 memcpy(s, t, len);
983                 s += len;
984         }
985         *s = 0;
986         return string;
987 }
988
989 static char *R_ShaderStrCat(const char **strings);
990 static void R_InitShaderModeInfo(void)
991 {
992         int i, language;
993         shadermodeinfo_t *modeinfo;
994         // 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)
995         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
996         {
997                 for (i = 0; i < SHADERMODE_COUNT; i++)
998                 {
999                         char filename[MAX_QPATH];
1000                         modeinfo = &shadermodeinfo[language][i];
1001                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1002                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1003                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1004                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1005                 }
1006         }
1007 }
1008
1009 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1010 {
1011         char *shaderstring;
1012         // if the mode has no filename we have to return the builtin string
1013         if (builtinonly || !modeinfo->filename)
1014                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1015         // note that FS_LoadFile appends a 0 byte to make it a valid string
1016         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1017         if (shaderstring)
1018         {
1019                 if (printfromdisknotice)
1020                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1021                 return shaderstring;
1022         }
1023         // fall back to builtinstring
1024         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1025 }
1026
1027 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1028 {
1029         int i;
1030         int ubibind;
1031         int sampler;
1032         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1033         char *sourcestring;
1034         char permutationname[256];
1035         int vertstrings_count = 0;
1036         int geomstrings_count = 0;
1037         int fragstrings_count = 0;
1038         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1039         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1040         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1041
1042         if (p->compiled)
1043                 return;
1044         p->compiled = true;
1045         p->program = 0;
1046
1047         permutationname[0] = 0;
1048         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1049
1050         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1051
1052         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1053         if(vid.support.glshaderversion >= 140)
1054         {
1055                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1056                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1057                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1058                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1059                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1060                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1061         }
1062         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1063         else if(vid.support.glshaderversion >= 130)
1064         {
1065                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1066                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1067                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1068                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1069                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1070                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1071         }
1072         // if we can do #version 120, we should (this adds the invariant keyword)
1073         else if(vid.support.glshaderversion >= 120)
1074         {
1075                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1076                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1077                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1078                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1079                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1080                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1081         }
1082         // GLES also adds several things from GLSL120
1083         switch(vid.renderpath)
1084         {
1085         case RENDERPATH_GLES2:
1086                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1087                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1088                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1089                 break;
1090         default:
1091                 break;
1092         }
1093
1094         // the first pretext is which type of shader to compile as
1095         // (later these will all be bound together as a program object)
1096         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1097         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1098         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1099
1100         // the second pretext is the mode (for example a light source)
1101         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1102         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1103         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1104         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1105
1106         // now add all the permutation pretexts
1107         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1108         {
1109                 if (permutation & (1ll<<i))
1110                 {
1111                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1112                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1113                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1114                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1115                 }
1116                 else
1117                 {
1118                         // keep line numbers correct
1119                         vertstrings_list[vertstrings_count++] = "\n";
1120                         geomstrings_list[geomstrings_count++] = "\n";
1121                         fragstrings_list[fragstrings_count++] = "\n";
1122                 }
1123         }
1124
1125         // add static parms
1126         R_CompileShader_AddStaticParms(mode, permutation);
1127         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1128         vertstrings_count += shaderstaticparms_count;
1129         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1130         geomstrings_count += shaderstaticparms_count;
1131         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1132         fragstrings_count += shaderstaticparms_count;
1133
1134         // now append the shader text itself
1135         vertstrings_list[vertstrings_count++] = sourcestring;
1136         geomstrings_list[geomstrings_count++] = sourcestring;
1137         fragstrings_list[fragstrings_count++] = sourcestring;
1138
1139         // we don't currently use geometry shaders for anything, so just empty the list
1140         geomstrings_count = 0;
1141
1142         // compile the shader program
1143         if (vertstrings_count + geomstrings_count + fragstrings_count)
1144                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1145         if (p->program)
1146         {
1147                 CHECKGLERROR
1148                 qglUseProgram(p->program);CHECKGLERROR
1149                 // look up all the uniform variable names we care about, so we don't
1150                 // have to look them up every time we set them
1151
1152 #if 0
1153                 // debugging aid
1154                 {
1155                         GLint activeuniformindex = 0;
1156                         GLint numactiveuniforms = 0;
1157                         char uniformname[128];
1158                         GLsizei uniformnamelength = 0;
1159                         GLint uniformsize = 0;
1160                         GLenum uniformtype = 0;
1161                         memset(uniformname, 0, sizeof(uniformname));
1162                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1163                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1164                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1165                         {
1166                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1167                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1168                         }
1169                 }
1170 #endif
1171
1172                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1173                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1174                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1175                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1176                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1177                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1178                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1179                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1180                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1181                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1182                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1183                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1184                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1185                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1186                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1187                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1188                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1189                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1190                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1191                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1192                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1193                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1194                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1195                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1196                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1197                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1198                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1199                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1200                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1201                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1202                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1203                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1204                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1205                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1206                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1207                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1208                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1209                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1210                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1211                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1212                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1213                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1214                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1215                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1216                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1217                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1218                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1219                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1220                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1221                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1222                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1223                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1224                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1225                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1226                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1227                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1228                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1229                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1230                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1231                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1232                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1233                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1234                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1235                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1236                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1237                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1238                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1239                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1240                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1241                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1242                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1243                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1244                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1245                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1246                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1247                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1248                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1249                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1250                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1251                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1252                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1253                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1254                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1255                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1256                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1257                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1258                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1259                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1260                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1261                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1262                 // initialize the samplers to refer to the texture units we use
1263                 p->tex_Texture_First = -1;
1264                 p->tex_Texture_Second = -1;
1265                 p->tex_Texture_GammaRamps = -1;
1266                 p->tex_Texture_Normal = -1;
1267                 p->tex_Texture_Color = -1;
1268                 p->tex_Texture_Gloss = -1;
1269                 p->tex_Texture_Glow = -1;
1270                 p->tex_Texture_SecondaryNormal = -1;
1271                 p->tex_Texture_SecondaryColor = -1;
1272                 p->tex_Texture_SecondaryGloss = -1;
1273                 p->tex_Texture_SecondaryGlow = -1;
1274                 p->tex_Texture_Pants = -1;
1275                 p->tex_Texture_Shirt = -1;
1276                 p->tex_Texture_FogHeightTexture = -1;
1277                 p->tex_Texture_FogMask = -1;
1278                 p->tex_Texture_LightGrid = -1;
1279                 p->tex_Texture_Lightmap = -1;
1280                 p->tex_Texture_Deluxemap = -1;
1281                 p->tex_Texture_Attenuation = -1;
1282                 p->tex_Texture_Cube = -1;
1283                 p->tex_Texture_Refraction = -1;
1284                 p->tex_Texture_Reflection = -1;
1285                 p->tex_Texture_ShadowMap2D = -1;
1286                 p->tex_Texture_CubeProjection = -1;
1287                 p->tex_Texture_ScreenNormalMap = -1;
1288                 p->tex_Texture_ScreenDiffuse = -1;
1289                 p->tex_Texture_ScreenSpecular = -1;
1290                 p->tex_Texture_ReflectMask = -1;
1291                 p->tex_Texture_ReflectCube = -1;
1292                 p->tex_Texture_BounceGrid = -1;
1293                 // bind the texture samplers in use
1294                 sampler = 0;
1295                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1296                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1297                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1298                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1299                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1300                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1301                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1302                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1303                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1304                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1305                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1306                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1307                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1308                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1309                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1310                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1311                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1312                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1313                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1314                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1315                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1316                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1317                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1318                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1319                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1320                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1321                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1322                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1323                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1324                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1325                 // get the uniform block indices so we can bind them
1326                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1327 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1328                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1329 #endif
1330                 // clear the uniform block bindings
1331                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1332                 // bind the uniform blocks in use
1333                 ubibind = 0;
1334 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1335                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1336 #endif
1337                 // we're done compiling and setting up the shader, at least until it is used
1338                 CHECKGLERROR
1339                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1340         }
1341         else
1342                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1343
1344         // free the strings
1345         if (sourcestring)
1346                 Mem_Free(sourcestring);
1347 }
1348
1349 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1350 {
1351         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1352         if (r_glsl_permutation != perm)
1353         {
1354                 r_glsl_permutation = perm;
1355                 if (!r_glsl_permutation->program)
1356                 {
1357                         if (!r_glsl_permutation->compiled)
1358                         {
1359                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1360                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1361                         }
1362                         if (!r_glsl_permutation->program)
1363                         {
1364                                 // remove features until we find a valid permutation
1365                                 int i;
1366                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1367                                 {
1368                                         // reduce i more quickly whenever it would not remove any bits
1369                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1370                                         if (!(permutation & j))
1371                                                 continue;
1372                                         permutation -= j;
1373                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1374                                         if (!r_glsl_permutation->compiled)
1375                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1376                                         if (r_glsl_permutation->program)
1377                                                 break;
1378                                 }
1379                                 if (i >= SHADERPERMUTATION_COUNT)
1380                                 {
1381                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1382                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1383                                         qglUseProgram(0);CHECKGLERROR
1384                                         return; // no bit left to clear, entire mode is broken
1385                                 }
1386                         }
1387                 }
1388                 CHECKGLERROR
1389                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1390         }
1391         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1392         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1393         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1394         CHECKGLERROR
1395 }
1396
1397 void R_GLSL_Restart_f(cmd_state_t *cmd)
1398 {
1399         unsigned int i, limit;
1400         switch(vid.renderpath)
1401         {
1402         case RENDERPATH_GL32:
1403         case RENDERPATH_GLES2:
1404                 {
1405                         r_glsl_permutation_t *p;
1406                         r_glsl_permutation = NULL;
1407                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1408                         for (i = 0;i < limit;i++)
1409                         {
1410                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1411                                 {
1412                                         GL_Backend_FreeProgram(p->program);
1413                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1414                                 }
1415                         }
1416                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1417                 }
1418                 break;
1419         }
1420 }
1421
1422 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1423 {
1424         int i, language, mode, dupe;
1425         char *text;
1426         shadermodeinfo_t *modeinfo;
1427         qfile_t *file;
1428
1429         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1430         {
1431                 modeinfo = shadermodeinfo[language];
1432                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1433                 {
1434                         // don't dump the same file multiple times (most or all shaders come from the same file)
1435                         for (dupe = mode - 1;dupe >= 0;dupe--)
1436                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1437                                         break;
1438                         if (dupe >= 0)
1439                                 continue;
1440                         text = modeinfo[mode].builtinstring;
1441                         if (!text)
1442                                 continue;
1443                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1444                         if (file)
1445                         {
1446                                 FS_Print(file, "/* The engine may define the following macros:\n");
1447                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1448                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1449                                         FS_Print(file, modeinfo[i].pretext);
1450                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1451                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1452                                 FS_Print(file, "*/\n");
1453                                 FS_Print(file, text);
1454                                 FS_Close(file);
1455                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1456                         }
1457                         else
1458                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1459                 }
1460         }
1461 }
1462
1463 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1464 {
1465         uint64_t permutation = 0;
1466         if (r_trippy.integer && !notrippy)
1467                 permutation |= SHADERPERMUTATION_TRIPPY;
1468         permutation |= SHADERPERMUTATION_VIEWTINT;
1469         if (t)
1470                 permutation |= SHADERPERMUTATION_DIFFUSE;
1471         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1472                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1473         if (suppresstexalpha)
1474                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1475         if (vid.allowalphatocoverage)
1476                 GL_AlphaToCoverage(false);
1477         switch (vid.renderpath)
1478         {
1479         case RENDERPATH_GL32:
1480         case RENDERPATH_GLES2:
1481                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1482                 if (r_glsl_permutation->tex_Texture_First >= 0)
1483                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1484                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1485                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1486                 break;
1487         }
1488 }
1489
1490 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1491 {
1492         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1493 }
1494
1495 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1496 {
1497         uint64_t permutation = 0;
1498         if (r_trippy.integer && !notrippy)
1499                 permutation |= SHADERPERMUTATION_TRIPPY;
1500         if (depthrgb)
1501                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1502         if (skeletal)
1503                 permutation |= SHADERPERMUTATION_SKELETAL;
1504
1505         if (vid.allowalphatocoverage)
1506                 GL_AlphaToCoverage(false);
1507         switch (vid.renderpath)
1508         {
1509         case RENDERPATH_GL32:
1510         case RENDERPATH_GLES2:
1511                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1512 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1513                 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);
1514 #endif
1515                 break;
1516         }
1517 }
1518
1519 #define BLENDFUNC_ALLOWS_COLORMOD      1
1520 #define BLENDFUNC_ALLOWS_FOG           2
1521 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1522 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1523 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1524 static int R_BlendFuncFlags(int src, int dst)
1525 {
1526         int r = 0;
1527
1528         // a blendfunc allows colormod if:
1529         // a) it can never keep the destination pixel invariant, or
1530         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1531         // this is to prevent unintended side effects from colormod
1532
1533         // a blendfunc allows fog if:
1534         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1535         // this is to prevent unintended side effects from fog
1536
1537         // these checks are the output of fogeval.pl
1538
1539         r |= BLENDFUNC_ALLOWS_COLORMOD;
1540         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1541         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1542         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1544         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1545         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1547         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1548         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1549         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1550         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1551         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1552         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1554         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1555         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1558         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1559         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1560         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1561
1562         return r;
1563 }
1564
1565 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)
1566 {
1567         // select a permutation of the lighting shader appropriate to this
1568         // combination of texture, entity, light source, and fogging, only use the
1569         // minimum features necessary to avoid wasting rendering time in the
1570         // fragment shader on features that are not being used
1571         uint64_t permutation = 0;
1572         unsigned int mode = 0;
1573         int blendfuncflags;
1574         texture_t *t = rsurface.texture;
1575         float m16f[16];
1576         matrix4x4_t tempmatrix;
1577         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1578         if (r_trippy.integer && !notrippy)
1579                 permutation |= SHADERPERMUTATION_TRIPPY;
1580         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1581                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1582         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1583                 permutation |= SHADERPERMUTATION_OCCLUDE;
1584         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1585                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1586         if (rsurfacepass == RSURFPASS_BACKGROUND)
1587         {
1588                 // distorted background
1589                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1590                 {
1591                         mode = SHADERMODE_WATER;
1592                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1593                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1594                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1595                         {
1596                                 // this is the right thing to do for wateralpha
1597                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1598                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1599                         }
1600                         else
1601                         {
1602                                 // this is the right thing to do for entity alpha
1603                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1604                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1605                         }
1606                 }
1607                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1608                 {
1609                         mode = SHADERMODE_REFRACTION;
1610                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1611                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1612                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1613                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1614                 }
1615                 else
1616                 {
1617                         mode = SHADERMODE_GENERIC;
1618                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1619                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1620                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1621                 }
1622                 if (vid.allowalphatocoverage)
1623                         GL_AlphaToCoverage(false);
1624         }
1625         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1626         {
1627                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1628                 {
1629                         switch(t->offsetmapping)
1630                         {
1631                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1632                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1633                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1634                         case OFFSETMAPPING_OFF: break;
1635                         }
1636                 }
1637                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1638                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1639                 // normalmap (deferred prepass), may use alpha test on diffuse
1640                 mode = SHADERMODE_DEFERREDGEOMETRY;
1641                 GL_BlendFunc(GL_ONE, GL_ZERO);
1642                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1643                 if (vid.allowalphatocoverage)
1644                         GL_AlphaToCoverage(false);
1645         }
1646         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1647         {
1648                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1649                 {
1650                         switch(t->offsetmapping)
1651                         {
1652                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1653                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1654                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1655                         case OFFSETMAPPING_OFF: break;
1656                         }
1657                 }
1658                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1659                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1660                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1661                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1662                 // light source
1663                 mode = SHADERMODE_LIGHTSOURCE;
1664                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1665                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1666                 if (VectorLength2(rtlightdiffuse) > 0)
1667                         permutation |= SHADERPERMUTATION_DIFFUSE;
1668                 if (VectorLength2(rtlightspecular) > 0)
1669                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1670                 if (r_refdef.fogenabled)
1671                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1672                 if (t->colormapping)
1673                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1674                 if (r_shadow_usingshadowmap2d)
1675                 {
1676                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1677                         if(r_shadow_shadowmapvsdct)
1678                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1679
1680                         if (r_shadow_shadowmap2ddepthbuffer)
1681                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1682                 }
1683                 if (t->reflectmasktexture)
1684                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1685                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1686                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1687                 if (vid.allowalphatocoverage)
1688                         GL_AlphaToCoverage(false);
1689         }
1690         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1691         {
1692                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1693                 {
1694                         switch(t->offsetmapping)
1695                         {
1696                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1697                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1698                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1699                         case OFFSETMAPPING_OFF: break;
1700                         }
1701                 }
1702                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1703                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1704                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1705                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1706                 // directional model lighting
1707                 mode = SHADERMODE_LIGHTGRID;
1708                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1709                         permutation |= SHADERPERMUTATION_GLOW;
1710                 permutation |= SHADERPERMUTATION_DIFFUSE;
1711                 if (t->glosstexture || t->backgroundglosstexture)
1712                         permutation |= SHADERPERMUTATION_SPECULAR;
1713                 if (r_refdef.fogenabled)
1714                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1715                 if (t->colormapping)
1716                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1717                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1718                 {
1719                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1720                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1721
1722                         if (r_shadow_shadowmap2ddepthbuffer)
1723                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1724                 }
1725                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1726                         permutation |= SHADERPERMUTATION_REFLECTION;
1727                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1728                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1729                 if (t->reflectmasktexture)
1730                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1731                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1732                 {
1733                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1734                         if (r_shadow_bouncegrid_state.directional)
1735                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1736                 }
1737                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1738                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1739                 // when using alphatocoverage, we don't need alphakill
1740                 if (vid.allowalphatocoverage)
1741                 {
1742                         if (r_transparent_alphatocoverage.integer)
1743                         {
1744                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1745                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1746                         }
1747                         else
1748                                 GL_AlphaToCoverage(false);
1749                 }
1750         }
1751         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1752         {
1753                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1754                 {
1755                         switch(t->offsetmapping)
1756                         {
1757                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1758                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1759                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1760                         case OFFSETMAPPING_OFF: break;
1761                         }
1762                 }
1763                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1764                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1765                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1766                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1767                 // directional model lighting
1768                 mode = SHADERMODE_LIGHTDIRECTION;
1769                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1770                         permutation |= SHADERPERMUTATION_GLOW;
1771                 if (VectorLength2(t->render_modellight_diffuse))
1772                         permutation |= SHADERPERMUTATION_DIFFUSE;
1773                 if (VectorLength2(t->render_modellight_specular) > 0)
1774                         permutation |= SHADERPERMUTATION_SPECULAR;
1775                 if (r_refdef.fogenabled)
1776                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1777                 if (t->colormapping)
1778                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1779                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1780                 {
1781                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1782                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1783
1784                         if (r_shadow_shadowmap2ddepthbuffer)
1785                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1786                 }
1787                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1788                         permutation |= SHADERPERMUTATION_REFLECTION;
1789                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1790                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1791                 if (t->reflectmasktexture)
1792                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1793                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1794                 {
1795                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1796                         if (r_shadow_bouncegrid_state.directional)
1797                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1798                 }
1799                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1800                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1801                 // when using alphatocoverage, we don't need alphakill
1802                 if (vid.allowalphatocoverage)
1803                 {
1804                         if (r_transparent_alphatocoverage.integer)
1805                         {
1806                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1807                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1808                         }
1809                         else
1810                                 GL_AlphaToCoverage(false);
1811                 }
1812         }
1813         else
1814         {
1815                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1816                 {
1817                         switch(t->offsetmapping)
1818                         {
1819                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1820                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1821                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1822                         case OFFSETMAPPING_OFF: break;
1823                         }
1824                 }
1825                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1826                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1827                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1828                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1829                 // lightmapped wall
1830                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1831                         permutation |= SHADERPERMUTATION_GLOW;
1832                 if (r_refdef.fogenabled && !ui)
1833                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1834                 if (t->colormapping)
1835                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1836                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1837                 {
1838                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1839                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1840
1841                         if (r_shadow_shadowmap2ddepthbuffer)
1842                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1843                 }
1844                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1845                         permutation |= SHADERPERMUTATION_REFLECTION;
1846                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1847                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1848                 if (t->reflectmasktexture)
1849                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1850                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1851                 {
1852                         // deluxemapping (light direction texture)
1853                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1854                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1855                         else
1856                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1857                         permutation |= SHADERPERMUTATION_DIFFUSE;
1858                         if (VectorLength2(t->render_lightmap_specular) > 0)
1859                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1860                 }
1861                 else if (r_glsl_deluxemapping.integer >= 2)
1862                 {
1863                         // fake deluxemapping (uniform light direction in tangentspace)
1864                         if (rsurface.uselightmaptexture)
1865                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1866                         else
1867                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1868                         permutation |= SHADERPERMUTATION_DIFFUSE;
1869                         if (VectorLength2(t->render_lightmap_specular) > 0)
1870                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1871                 }
1872                 else if (rsurface.uselightmaptexture)
1873                 {
1874                         // ordinary lightmapping (q1bsp, q3bsp)
1875                         mode = SHADERMODE_LIGHTMAP;
1876                 }
1877                 else
1878                 {
1879                         // ordinary vertex coloring (q3bsp)
1880                         mode = SHADERMODE_VERTEXCOLOR;
1881                 }
1882                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1883                 {
1884                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1885                         if (r_shadow_bouncegrid_state.directional)
1886                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1887                 }
1888                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1889                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1890                 // when using alphatocoverage, we don't need alphakill
1891                 if (vid.allowalphatocoverage)
1892                 {
1893                         if (r_transparent_alphatocoverage.integer)
1894                         {
1895                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1896                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1897                         }
1898                         else
1899                                 GL_AlphaToCoverage(false);
1900                 }
1901         }
1902         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1903                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1904         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1905                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1906         switch(vid.renderpath)
1907         {
1908         case RENDERPATH_GL32:
1909         case RENDERPATH_GLES2:
1910                 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);
1911                 RSurf_UploadBuffersForBatch();
1912                 // this has to be after RSurf_PrepareVerticesForBatch
1913                 if (rsurface.batchskeletaltransform3x4buffer)
1914                         permutation |= SHADERPERMUTATION_SKELETAL;
1915                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1916 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1917                 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);
1918 #endif
1919                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1920                 if (mode == SHADERMODE_LIGHTSOURCE)
1921                 {
1922                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1923                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1924                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1925                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1926                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1927                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1928         
1929                         // additive passes are only darkened by fog, not tinted
1930                         if (r_glsl_permutation->loc_FogColor >= 0)
1931                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1932                         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);
1933                 }
1934                 else
1935                 {
1936                         if (mode == SHADERMODE_FLATCOLOR)
1937                         {
1938                                 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]);
1939                         }
1940                         else if (mode == SHADERMODE_LIGHTGRID)
1941                         {
1942                                 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]);
1943                                 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]);
1944                                 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]);
1945                                 // other LightGrid uniforms handled below
1946                         }
1947                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1948                         {
1949                                 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]);
1950                                 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]);
1951                                 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]);
1952                                 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]);
1953                                 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]);
1954                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1955                                 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]);
1956                         }
1957                         else
1958                         {
1959                                 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]);
1960                                 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]);
1961                                 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]);
1962                                 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]);
1963                                 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]);
1964                         }
1965                         // additive passes are only darkened by fog, not tinted
1966                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1967                         {
1968                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1969                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1970                                 else
1971                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1972                         }
1973                         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);
1974                         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]);
1975                         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]);
1976                         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);
1977                         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);
1978                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1979                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1980                         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);
1981                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1982                 }
1983                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1984                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1985                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1986                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1987                 {
1988                         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]);
1989                         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]);
1990                 }
1991                 else
1992                 {
1993                         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]);
1994                         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]);
1995                 }
1996
1997                 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]);
1998                 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));
1999                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2000                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2001                 {
2002                         if (t->pantstexture)
2003                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2004                         else
2005                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2006                 }
2007                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2008                 {
2009                         if (t->shirttexture)
2010                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2011                         else
2012                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2013                 }
2014                 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]);
2015                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2016                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2017                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2018                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2019                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2020                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2021                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2022                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2023                         );
2024                 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);
2025                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2026                 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]);
2027                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2028                 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);}
2029                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2030                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2031                 {
2032                         float m9f[9];
2033                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2034                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2035                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2036                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2037                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2038                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2039                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2040                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2041                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2042                 }
2043
2044                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2045                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2046                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2047                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2048                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2049                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2050                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2051                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2052                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2053                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2054                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2055                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2056                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2057                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2058                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2059                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2060                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2061                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2062                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2063                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2064                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2065                 {
2066                         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);
2067                         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);
2068                         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);
2069                 }
2070                 else
2071                 {
2072                         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);
2073                 }
2074                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2075                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2076                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2077                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2078                 {
2079                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2080                         if (rsurface.rtlight)
2081                         {
2082                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2083                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2084                         }
2085                 }
2086                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2087                 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);
2088                 CHECKGLERROR
2089                 break;
2090         }
2091 }
2092
2093 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2094 {
2095         // select a permutation of the lighting shader appropriate to this
2096         // combination of texture, entity, light source, and fogging, only use the
2097         // minimum features necessary to avoid wasting rendering time in the
2098         // fragment shader on features that are not being used
2099         uint64_t permutation = 0;
2100         unsigned int mode = 0;
2101         const float *lightcolorbase = rtlight->currentcolor;
2102         float ambientscale = rtlight->ambientscale;
2103         float diffusescale = rtlight->diffusescale;
2104         float specularscale = rtlight->specularscale;
2105         // this is the location of the light in view space
2106         vec3_t viewlightorigin;
2107         // this transforms from view space (camera) to light space (cubemap)
2108         matrix4x4_t viewtolight;
2109         matrix4x4_t lighttoview;
2110         float viewtolight16f[16];
2111         // light source
2112         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2113         if (rtlight->currentcubemap != r_texture_whitecube)
2114                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2115         if (diffusescale > 0)
2116                 permutation |= SHADERPERMUTATION_DIFFUSE;
2117         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2118                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2119         if (r_shadow_usingshadowmap2d)
2120         {
2121                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2122                 if (r_shadow_shadowmapvsdct)
2123                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2124
2125                 if (r_shadow_shadowmap2ddepthbuffer)
2126                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2127         }
2128         if (vid.allowalphatocoverage)
2129                 GL_AlphaToCoverage(false);
2130         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2131         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2132         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2133         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2134         switch(vid.renderpath)
2135         {
2136         case RENDERPATH_GL32:
2137         case RENDERPATH_GLES2:
2138                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2139                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2140                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2141                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2142                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2143                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2144                 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]);
2145                 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]);
2146                 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);
2147                 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]);
2148                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2149
2150                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2151                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2152                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2153                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2154                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2155                 break;
2156         }
2157 }
2158
2159 #define SKINFRAME_HASH 1024
2160
2161 typedef struct
2162 {
2163         unsigned int loadsequence; // incremented each level change
2164         memexpandablearray_t array;
2165         skinframe_t *hash[SKINFRAME_HASH];
2166 }
2167 r_skinframe_t;
2168 r_skinframe_t r_skinframe;
2169
2170 void R_SkinFrame_PrepareForPurge(void)
2171 {
2172         r_skinframe.loadsequence++;
2173         // wrap it without hitting zero
2174         if (r_skinframe.loadsequence >= 200)
2175                 r_skinframe.loadsequence = 1;
2176 }
2177
2178 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2179 {
2180         if (!skinframe)
2181                 return;
2182         // mark the skinframe as used for the purging code
2183         skinframe->loadsequence = r_skinframe.loadsequence;
2184 }
2185
2186 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2187 {
2188         if (s == NULL)
2189                 return;
2190         if (s->merged == s->base)
2191                 s->merged = NULL;
2192         R_PurgeTexture(s->stain); s->stain = NULL;
2193         R_PurgeTexture(s->merged); s->merged = NULL;
2194         R_PurgeTexture(s->base); s->base = NULL;
2195         R_PurgeTexture(s->pants); s->pants = NULL;
2196         R_PurgeTexture(s->shirt); s->shirt = NULL;
2197         R_PurgeTexture(s->nmap); s->nmap = NULL;
2198         R_PurgeTexture(s->gloss); s->gloss = NULL;
2199         R_PurgeTexture(s->glow); s->glow = NULL;
2200         R_PurgeTexture(s->fog); s->fog = NULL;
2201         R_PurgeTexture(s->reflect); s->reflect = NULL;
2202         s->loadsequence = 0;
2203 }
2204
2205 void R_SkinFrame_Purge(void)
2206 {
2207         int i;
2208         skinframe_t *s;
2209         for (i = 0;i < SKINFRAME_HASH;i++)
2210         {
2211                 for (s = r_skinframe.hash[i];s;s = s->next)
2212                 {
2213                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2214                                 R_SkinFrame_PurgeSkinFrame(s);
2215                 }
2216         }
2217 }
2218
2219 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2220         skinframe_t *item;
2221         char basename[MAX_QPATH];
2222
2223         Image_StripImageExtension(name, basename, sizeof(basename));
2224
2225         if( last == NULL ) {
2226                 int hashindex;
2227                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2228                 item = r_skinframe.hash[hashindex];
2229         } else {
2230                 item = last->next;
2231         }
2232
2233         // linearly search through the hash bucket
2234         for( ; item ; item = item->next ) {
2235                 if( !strcmp( item->basename, basename ) ) {
2236                         return item;
2237                 }
2238         }
2239         return NULL;
2240 }
2241
2242 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2243 {
2244         skinframe_t *item;
2245         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2246         int hashindex;
2247         char basename[MAX_QPATH];
2248
2249         Image_StripImageExtension(name, basename, sizeof(basename));
2250
2251         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2252         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2253                 if (!strcmp(item->basename, basename) &&
2254                         item->textureflags == compareflags &&
2255                         item->comparewidth == comparewidth &&
2256                         item->compareheight == compareheight &&
2257                         item->comparecrc == comparecrc)
2258                         break;
2259
2260         if (!item)
2261         {
2262                 if (!add)
2263                         return NULL;
2264                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2265                 memset(item, 0, sizeof(*item));
2266                 strlcpy(item->basename, basename, sizeof(item->basename));
2267                 item->textureflags = compareflags;
2268                 item->comparewidth = comparewidth;
2269                 item->compareheight = compareheight;
2270                 item->comparecrc = comparecrc;
2271                 item->next = r_skinframe.hash[hashindex];
2272                 r_skinframe.hash[hashindex] = item;
2273         }
2274         else if (textureflags & TEXF_FORCE_RELOAD)
2275                 R_SkinFrame_PurgeSkinFrame(item);
2276
2277         R_SkinFrame_MarkUsed(item);
2278         return item;
2279 }
2280
2281 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2282         { \
2283                 unsigned long long avgcolor[5], wsum; \
2284                 int pix, comp, w; \
2285                 avgcolor[0] = 0; \
2286                 avgcolor[1] = 0; \
2287                 avgcolor[2] = 0; \
2288                 avgcolor[3] = 0; \
2289                 avgcolor[4] = 0; \
2290                 wsum = 0; \
2291                 for(pix = 0; pix < cnt; ++pix) \
2292                 { \
2293                         w = 0; \
2294                         for(comp = 0; comp < 3; ++comp) \
2295                                 w += getpixel; \
2296                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2297                         { \
2298                                 ++wsum; \
2299                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2300                                 w = getpixel; \
2301                                 for(comp = 0; comp < 3; ++comp) \
2302                                         avgcolor[comp] += getpixel * w; \
2303                                 avgcolor[3] += w; \
2304                         } \
2305                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2306                         avgcolor[4] += getpixel; \
2307                 } \
2308                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2309                         avgcolor[3] = 1; \
2310                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2311                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2312                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2313                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2314         }
2315
2316 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2317 {
2318         skinframe_t *skinframe;
2319
2320         if (cls.state == ca_dedicated)
2321                 return NULL;
2322
2323         // return an existing skinframe if already loaded
2324         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2325         if (skinframe && skinframe->base)
2326                 return skinframe;
2327
2328         // if the skinframe doesn't exist this will create it
2329         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2330 }
2331
2332 extern cvar_t gl_picmip;
2333 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2334 {
2335         int j;
2336         unsigned char *pixels;
2337         unsigned char *bumppixels;
2338         unsigned char *basepixels = NULL;
2339         int basepixels_width = 0;
2340         int basepixels_height = 0;
2341         rtexture_t *ddsbase = NULL;
2342         qbool ddshasalpha = false;
2343         float ddsavgcolor[4];
2344         char basename[MAX_QPATH];
2345         int miplevel = R_PicmipForFlags(textureflags);
2346         int savemiplevel = miplevel;
2347         int mymiplevel;
2348         char vabuf[1024];
2349
2350         if (cls.state == ca_dedicated)
2351                 return NULL;
2352
2353         Image_StripImageExtension(name, basename, sizeof(basename));
2354
2355         // check for DDS texture file first
2356         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2357         {
2358                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2359                 if (basepixels == NULL && fallbacknotexture)
2360                         basepixels = Image_GenerateNoTexture();
2361                 if (basepixels == NULL)
2362                         return NULL;
2363         }
2364
2365         // FIXME handle miplevel
2366
2367         if (developer_loading.integer)
2368                 Con_Printf("loading skin \"%s\"\n", name);
2369
2370         // we've got some pixels to store, so really allocate this new texture now
2371         if (!skinframe)
2372                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2373         textureflags &= ~TEXF_FORCE_RELOAD;
2374         skinframe->stain = NULL;
2375         skinframe->merged = NULL;
2376         skinframe->base = NULL;
2377         skinframe->pants = NULL;
2378         skinframe->shirt = NULL;
2379         skinframe->nmap = NULL;
2380         skinframe->gloss = NULL;
2381         skinframe->glow = NULL;
2382         skinframe->fog = NULL;
2383         skinframe->reflect = NULL;
2384         skinframe->hasalpha = false;
2385         // we could store the q2animname here too
2386
2387         if (ddsbase)
2388         {
2389                 skinframe->base = ddsbase;
2390                 skinframe->hasalpha = ddshasalpha;
2391                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2392                 if (r_loadfog && skinframe->hasalpha)
2393                         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);
2394                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2395         }
2396         else
2397         {
2398                 basepixels_width = image_width;
2399                 basepixels_height = image_height;
2400                 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);
2401                 if (textureflags & TEXF_ALPHA)
2402                 {
2403                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2404                         {
2405                                 if (basepixels[j] < 255)
2406                                 {
2407                                         skinframe->hasalpha = true;
2408                                         break;
2409                                 }
2410                         }
2411                         if (r_loadfog && skinframe->hasalpha)
2412                         {
2413                                 // has transparent pixels
2414                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2415                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2416                                 {
2417                                         pixels[j+0] = 255;
2418                                         pixels[j+1] = 255;
2419                                         pixels[j+2] = 255;
2420                                         pixels[j+3] = basepixels[j+3];
2421                                 }
2422                                 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);
2423                                 Mem_Free(pixels);
2424                         }
2425                 }
2426                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2427 #ifndef USE_GLES2
2428                 //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]);
2429                 if (r_savedds && skinframe->base)
2430                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2431                 if (r_savedds && skinframe->fog)
2432                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2433 #endif
2434         }
2435
2436         if (r_loaddds)
2437         {
2438                 mymiplevel = savemiplevel;
2439                 if (r_loadnormalmap)
2440                         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);
2441                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2442                 if (r_loadgloss)
2443                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2444                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2445                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2446                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2447         }
2448
2449         // _norm is the name used by tenebrae and has been adopted as standard
2450         if (r_loadnormalmap && skinframe->nmap == NULL)
2451         {
2452                 mymiplevel = savemiplevel;
2453                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2454                 {
2455                         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);
2456                         Mem_Free(pixels);
2457                         pixels = NULL;
2458                 }
2459                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2460                 {
2461                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2462                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2463                         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);
2464                         Mem_Free(pixels);
2465                         Mem_Free(bumppixels);
2466                 }
2467                 else if (r_shadow_bumpscale_basetexture.value > 0)
2468                 {
2469                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2470                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2471                         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);
2472                         Mem_Free(pixels);
2473                 }
2474 #ifndef USE_GLES2
2475                 if (r_savedds && skinframe->nmap)
2476                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2477 #endif
2478         }
2479
2480         // _luma is supported only for tenebrae compatibility
2481         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2482         // _glow is the preferred name
2483         mymiplevel = savemiplevel;
2484         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))))
2485         {
2486                 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);
2487 #ifndef USE_GLES2
2488                 if (r_savedds && skinframe->glow)
2489                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2490 #endif
2491                 Mem_Free(pixels);pixels = NULL;
2492         }
2493
2494         mymiplevel = savemiplevel;
2495         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2496         {
2497                 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);
2498 #ifndef USE_GLES2
2499                 if (r_savedds && skinframe->gloss)
2500                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2501 #endif
2502                 Mem_Free(pixels);
2503                 pixels = NULL;
2504         }
2505
2506         mymiplevel = savemiplevel;
2507         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2508         {
2509                 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);
2510 #ifndef USE_GLES2
2511                 if (r_savedds && skinframe->pants)
2512                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2513 #endif
2514                 Mem_Free(pixels);
2515                 pixels = NULL;
2516         }
2517
2518         mymiplevel = savemiplevel;
2519         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2520         {
2521                 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);
2522 #ifndef USE_GLES2
2523                 if (r_savedds && skinframe->shirt)
2524                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2525 #endif
2526                 Mem_Free(pixels);
2527                 pixels = NULL;
2528         }
2529
2530         mymiplevel = savemiplevel;
2531         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2532         {
2533                 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);
2534 #ifndef USE_GLES2
2535                 if (r_savedds && skinframe->reflect)
2536                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2537 #endif
2538                 Mem_Free(pixels);
2539                 pixels = NULL;
2540         }
2541
2542         if (basepixels)
2543                 Mem_Free(basepixels);
2544
2545         return skinframe;
2546 }
2547
2548 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)
2549 {
2550         int i;
2551         skinframe_t *skinframe;
2552         char vabuf[1024];
2553
2554         if (cls.state == ca_dedicated)
2555                 return NULL;
2556
2557         // if already loaded just return it, otherwise make a new skinframe
2558         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2559         if (skinframe->base)
2560                 return skinframe;
2561         textureflags &= ~TEXF_FORCE_RELOAD;
2562
2563         skinframe->stain = NULL;
2564         skinframe->merged = NULL;
2565         skinframe->base = NULL;
2566         skinframe->pants = NULL;
2567         skinframe->shirt = NULL;
2568         skinframe->nmap = NULL;
2569         skinframe->gloss = NULL;
2570         skinframe->glow = NULL;
2571         skinframe->fog = NULL;
2572         skinframe->reflect = NULL;
2573         skinframe->hasalpha = false;
2574
2575         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2576         if (!skindata)
2577                 return NULL;
2578
2579         if (developer_loading.integer)
2580                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2581
2582         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2583         {
2584                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2585                 unsigned char *b = a + width * height * 4;
2586                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2587                 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);
2588                 Mem_Free(a);
2589         }
2590         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2591         if (textureflags & TEXF_ALPHA)
2592         {
2593                 for (i = 3;i < width * height * 4;i += 4)
2594                 {
2595                         if (skindata[i] < 255)
2596                         {
2597                                 skinframe->hasalpha = true;
2598                                 break;
2599                         }
2600                 }
2601                 if (r_loadfog && skinframe->hasalpha)
2602                 {
2603                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2604                         memcpy(fogpixels, skindata, width * height * 4);
2605                         for (i = 0;i < width * height * 4;i += 4)
2606                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2607                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2608                         Mem_Free(fogpixels);
2609                 }
2610         }
2611
2612         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2613         //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]);
2614
2615         return skinframe;
2616 }
2617
2618 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2619 {
2620         int i;
2621         int featuresmask;
2622         skinframe_t *skinframe;
2623
2624         if (cls.state == ca_dedicated)
2625                 return NULL;
2626
2627         // if already loaded just return it, otherwise make a new skinframe
2628         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2629         if (skinframe->base)
2630                 return skinframe;
2631         //textureflags &= ~TEXF_FORCE_RELOAD;
2632
2633         skinframe->stain = NULL;
2634         skinframe->merged = NULL;
2635         skinframe->base = NULL;
2636         skinframe->pants = NULL;
2637         skinframe->shirt = NULL;
2638         skinframe->nmap = NULL;
2639         skinframe->gloss = NULL;
2640         skinframe->glow = NULL;
2641         skinframe->fog = NULL;
2642         skinframe->reflect = NULL;
2643         skinframe->hasalpha = false;
2644
2645         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2646         if (!skindata)
2647                 return NULL;
2648
2649         if (developer_loading.integer)
2650                 Con_Printf("loading quake skin \"%s\"\n", name);
2651
2652         // 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)
2653         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2654         memcpy(skinframe->qpixels, skindata, width*height);
2655         skinframe->qwidth = width;
2656         skinframe->qheight = height;
2657
2658         featuresmask = 0;
2659         for (i = 0;i < width * height;i++)
2660                 featuresmask |= palette_featureflags[skindata[i]];
2661
2662         skinframe->hasalpha = false;
2663         // fence textures
2664         if (name[0] == '{')
2665                 skinframe->hasalpha = true;
2666         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2667         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2668         skinframe->qgeneratemerged = true;
2669         skinframe->qgeneratebase = skinframe->qhascolormapping;
2670         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2671
2672         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2673         //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]);
2674
2675         return skinframe;
2676 }
2677
2678 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2679 {
2680         int width;
2681         int height;
2682         unsigned char *skindata;
2683         char vabuf[1024];
2684
2685         if (!skinframe->qpixels)
2686                 return;
2687
2688         if (!skinframe->qhascolormapping)
2689                 colormapped = false;
2690
2691         if (colormapped)
2692         {
2693                 if (!skinframe->qgeneratebase)
2694                         return;
2695         }
2696         else
2697         {
2698                 if (!skinframe->qgeneratemerged)
2699                         return;
2700         }
2701
2702         width = skinframe->qwidth;
2703         height = skinframe->qheight;
2704         skindata = skinframe->qpixels;
2705
2706         if (skinframe->qgeneratenmap)
2707         {
2708                 unsigned char *a, *b;
2709                 skinframe->qgeneratenmap = false;
2710                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2711                 b = a + width * height * 4;
2712                 // use either a custom palette or the quake palette
2713                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2714                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2715                 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);
2716                 Mem_Free(a);
2717         }
2718
2719         if (skinframe->qgenerateglow)
2720         {
2721                 skinframe->qgenerateglow = false;
2722                 if (skinframe->hasalpha) // fence textures
2723                         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
2724                 else
2725                         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
2726         }
2727
2728         if (colormapped)
2729         {
2730                 skinframe->qgeneratebase = false;
2731                 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);
2732                 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);
2733                 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);
2734         }
2735         else
2736         {
2737                 skinframe->qgeneratemerged = false;
2738                 if (skinframe->hasalpha) // fence textures
2739                         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);
2740                 else
2741                         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);
2742         }
2743
2744         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2745         {
2746                 Mem_Free(skinframe->qpixels);
2747                 skinframe->qpixels = NULL;
2748         }
2749 }
2750
2751 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)
2752 {
2753         int i;
2754         skinframe_t *skinframe;
2755         char vabuf[1024];
2756
2757         if (cls.state == ca_dedicated)
2758                 return NULL;
2759
2760         // if already loaded just return it, otherwise make a new skinframe
2761         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2762         if (skinframe->base)
2763                 return skinframe;
2764         textureflags &= ~TEXF_FORCE_RELOAD;
2765
2766         skinframe->stain = NULL;
2767         skinframe->merged = NULL;
2768         skinframe->base = NULL;
2769         skinframe->pants = NULL;
2770         skinframe->shirt = NULL;
2771         skinframe->nmap = NULL;
2772         skinframe->gloss = NULL;
2773         skinframe->glow = NULL;
2774         skinframe->fog = NULL;
2775         skinframe->reflect = NULL;
2776         skinframe->hasalpha = false;
2777
2778         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2779         if (!skindata)
2780                 return NULL;
2781
2782         if (developer_loading.integer)
2783                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2784
2785         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2786         if ((textureflags & TEXF_ALPHA) && alphapalette)
2787         {
2788                 for (i = 0;i < width * height;i++)
2789                 {
2790                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2791                         {
2792                                 skinframe->hasalpha = true;
2793                                 break;
2794                         }
2795                 }
2796                 if (r_loadfog && skinframe->hasalpha)
2797                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2798         }
2799
2800         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2801         //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]);
2802
2803         return skinframe;
2804 }
2805
2806 skinframe_t *R_SkinFrame_LoadMissing(void)
2807 {
2808         skinframe_t *skinframe;
2809
2810         if (cls.state == ca_dedicated)
2811                 return NULL;
2812
2813         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2814         skinframe->stain = NULL;
2815         skinframe->merged = NULL;
2816         skinframe->base = NULL;
2817         skinframe->pants = NULL;
2818         skinframe->shirt = NULL;
2819         skinframe->nmap = NULL;
2820         skinframe->gloss = NULL;
2821         skinframe->glow = NULL;
2822         skinframe->fog = NULL;
2823         skinframe->reflect = NULL;
2824         skinframe->hasalpha = false;
2825
2826         skinframe->avgcolor[0] = rand() / RAND_MAX;
2827         skinframe->avgcolor[1] = rand() / RAND_MAX;
2828         skinframe->avgcolor[2] = rand() / RAND_MAX;
2829         skinframe->avgcolor[3] = 1;
2830
2831         return skinframe;
2832 }
2833
2834 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2835 {
2836         if (cls.state == ca_dedicated)
2837                 return NULL;
2838
2839         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2840 }
2841
2842 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2843 {
2844         skinframe_t *skinframe;
2845         if (cls.state == ca_dedicated)
2846                 return NULL;
2847         // if already loaded just return it, otherwise make a new skinframe
2848         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2849         if (skinframe->base)
2850                 return skinframe;
2851         textureflags &= ~TEXF_FORCE_RELOAD;
2852         skinframe->stain = NULL;
2853         skinframe->merged = NULL;
2854         skinframe->base = NULL;
2855         skinframe->pants = NULL;
2856         skinframe->shirt = NULL;
2857         skinframe->nmap = NULL;
2858         skinframe->gloss = NULL;
2859         skinframe->glow = NULL;
2860         skinframe->fog = NULL;
2861         skinframe->reflect = NULL;
2862         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2863         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2864         if (!tex)
2865                 return NULL;
2866         if (developer_loading.integer)
2867                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2868         skinframe->base = skinframe->merged = tex;
2869         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2870         return skinframe;
2871 }
2872
2873 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2874 typedef struct suffixinfo_s
2875 {
2876         const char *suffix;
2877         qbool flipx, flipy, flipdiagonal;
2878 }
2879 suffixinfo_t;
2880 static suffixinfo_t suffix[3][6] =
2881 {
2882         {
2883                 {"px",   false, false, false},
2884                 {"nx",   false, false, false},
2885                 {"py",   false, false, false},
2886                 {"ny",   false, false, false},
2887                 {"pz",   false, false, false},
2888                 {"nz",   false, false, false}
2889         },
2890         {
2891                 {"posx", false, false, false},
2892                 {"negx", false, false, false},
2893                 {"posy", false, false, false},
2894                 {"negy", false, false, false},
2895                 {"posz", false, false, false},
2896                 {"negz", false, false, false}
2897         },
2898         {
2899                 {"rt",    true, false,  true},
2900                 {"lf",   false,  true,  true},
2901                 {"ft",    true,  true, false},
2902                 {"bk",   false, false, false},
2903                 {"up",    true, false,  true},
2904                 {"dn",    true, false,  true}
2905         }
2906 };
2907
2908 static int componentorder[4] = {0, 1, 2, 3};
2909
2910 static rtexture_t *R_LoadCubemap(const char *basename)
2911 {
2912         int i, j, cubemapsize, forcefilter;
2913         unsigned char *cubemappixels, *image_buffer;
2914         rtexture_t *cubemaptexture;
2915         char name[256];
2916
2917         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2918         forcefilter = TEXF_FORCELINEAR;
2919         if (basename && basename[0] == '!')
2920         {
2921                 basename++;
2922                 forcefilter = TEXF_FORCENEAREST;
2923         }
2924         // must start 0 so the first loadimagepixels has no requested width/height
2925         cubemapsize = 0;
2926         cubemappixels = NULL;
2927         cubemaptexture = NULL;
2928         // keep trying different suffix groups (posx, px, rt) until one loads
2929         for (j = 0;j < 3 && !cubemappixels;j++)
2930         {
2931                 // load the 6 images in the suffix group
2932                 for (i = 0;i < 6;i++)
2933                 {
2934                         // generate an image name based on the base and and suffix
2935                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2936                         // load it
2937                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2938                         {
2939                                 // an image loaded, make sure width and height are equal
2940                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2941                                 {
2942                                         // if this is the first image to load successfully, allocate the cubemap memory
2943                                         if (!cubemappixels && image_width >= 1)
2944                                         {
2945                                                 cubemapsize = image_width;
2946                                                 // note this clears to black, so unavailable sides are black
2947                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2948                                         }
2949                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2950                                         if (cubemappixels)
2951                                                 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);
2952                                 }
2953                                 else
2954                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2955                                 // free the image
2956                                 Mem_Free(image_buffer);
2957                         }
2958                 }
2959         }
2960         // if a cubemap loaded, upload it
2961         if (cubemappixels)
2962         {
2963                 if (developer_loading.integer)
2964                         Con_Printf("loading cubemap \"%s\"\n", basename);
2965
2966                 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);
2967                 Mem_Free(cubemappixels);
2968         }
2969         else
2970         {
2971                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2972                 if (developer_loading.integer)
2973                 {
2974                         Con_Printf("(tried tried images ");
2975                         for (j = 0;j < 3;j++)
2976                                 for (i = 0;i < 6;i++)
2977                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2978                         Con_Print(" and was unable to find any of them).\n");
2979                 }
2980         }
2981         return cubemaptexture;
2982 }
2983
2984 rtexture_t *R_GetCubemap(const char *basename)
2985 {
2986         int i;
2987         for (i = 0;i < r_texture_numcubemaps;i++)
2988                 if (r_texture_cubemaps[i] != NULL)
2989                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2990                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2991         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2992                 return r_texture_whitecube;
2993         r_texture_numcubemaps++;
2994         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2995         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2996         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2997         return r_texture_cubemaps[i]->texture;
2998 }
2999
3000 static void R_Main_FreeViewCache(void)
3001 {
3002         if (r_refdef.viewcache.entityvisible)
3003                 Mem_Free(r_refdef.viewcache.entityvisible);
3004         if (r_refdef.viewcache.world_pvsbits)
3005                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3006         if (r_refdef.viewcache.world_leafvisible)
3007                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3008         if (r_refdef.viewcache.world_surfacevisible)
3009                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3010         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3011 }
3012
3013 static void R_Main_ResizeViewCache(void)
3014 {
3015         int numentities = r_refdef.scene.numentities;
3016         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3017         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3018         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3019         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3020         if (r_refdef.viewcache.maxentities < numentities)
3021         {
3022                 r_refdef.viewcache.maxentities = numentities;
3023                 if (r_refdef.viewcache.entityvisible)
3024                         Mem_Free(r_refdef.viewcache.entityvisible);
3025                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3026         }
3027         if (r_refdef.viewcache.world_numclusters != numclusters)
3028         {
3029                 r_refdef.viewcache.world_numclusters = numclusters;
3030                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3031                 if (r_refdef.viewcache.world_pvsbits)
3032                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3033                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3034         }
3035         if (r_refdef.viewcache.world_numleafs != numleafs)
3036         {
3037                 r_refdef.viewcache.world_numleafs = numleafs;
3038                 if (r_refdef.viewcache.world_leafvisible)
3039                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3040                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3041         }
3042         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3043         {
3044                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3045                 if (r_refdef.viewcache.world_surfacevisible)
3046                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3047                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3048         }
3049 }
3050
3051 extern rtexture_t *loadingscreentexture;
3052 static void gl_main_start(void)
3053 {
3054         loadingscreentexture = NULL;
3055         r_texture_blanknormalmap = NULL;
3056         r_texture_white = NULL;
3057         r_texture_grey128 = NULL;
3058         r_texture_black = NULL;
3059         r_texture_whitecube = NULL;
3060         r_texture_normalizationcube = NULL;
3061         r_texture_fogattenuation = NULL;
3062         r_texture_fogheighttexture = NULL;
3063         r_texture_gammaramps = NULL;
3064         r_texture_numcubemaps = 0;
3065         r_uniformbufferalignment = 32;
3066
3067         r_loaddds = r_texture_dds_load.integer != 0;
3068         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3069
3070         switch(vid.renderpath)
3071         {
3072         case RENDERPATH_GL32:
3073         case RENDERPATH_GLES2:
3074                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3075                 Cvar_SetValueQuick(&gl_combine, 1);
3076                 Cvar_SetValueQuick(&r_glsl, 1);
3077                 r_loadnormalmap = true;
3078                 r_loadgloss = true;
3079                 r_loadfog = false;
3080 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3081                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3082 #endif
3083                 break;
3084         }
3085
3086         R_AnimCache_Free();
3087         R_FrameData_Reset();
3088         R_BufferData_Reset();
3089
3090         r_numqueries = 0;
3091         r_maxqueries = 0;
3092         memset(r_queries, 0, sizeof(r_queries));
3093
3094         r_qwskincache = NULL;
3095         r_qwskincache_size = 0;
3096
3097         // due to caching of texture_t references, the collision cache must be reset
3098         Collision_Cache_Reset(true);
3099
3100         // set up r_skinframe loading system for textures
3101         memset(&r_skinframe, 0, sizeof(r_skinframe));
3102         r_skinframe.loadsequence = 1;
3103         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3104
3105         r_main_texturepool = R_AllocTexturePool();
3106         R_BuildBlankTextures();
3107         R_BuildNoTexture();
3108         R_BuildWhiteCube();
3109 #ifndef USE_GLES2
3110         R_BuildNormalizationCube();
3111 #endif //USE_GLES2
3112         r_texture_fogattenuation = NULL;
3113         r_texture_fogheighttexture = NULL;
3114         r_texture_gammaramps = NULL;
3115         //r_texture_fogintensity = NULL;
3116         memset(&r_fb, 0, sizeof(r_fb));
3117         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3118         r_glsl_permutation = NULL;
3119         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3120         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3121         memset(&r_svbsp, 0, sizeof (r_svbsp));
3122
3123         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3124         r_texture_numcubemaps = 0;
3125
3126         r_refdef.fogmasktable_density = 0;
3127
3128 #ifdef __ANDROID__
3129         // For Steelstorm Android
3130         // FIXME CACHE the program and reload
3131         // FIXME see possible combinations for SS:BR android
3132         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3133         R_SetupShader_SetPermutationGLSL(0, 12);
3134         R_SetupShader_SetPermutationGLSL(0, 13);
3135         R_SetupShader_SetPermutationGLSL(0, 8388621);
3136         R_SetupShader_SetPermutationGLSL(3, 0);
3137         R_SetupShader_SetPermutationGLSL(3, 2048);
3138         R_SetupShader_SetPermutationGLSL(5, 0);
3139         R_SetupShader_SetPermutationGLSL(5, 2);
3140         R_SetupShader_SetPermutationGLSL(5, 2048);
3141         R_SetupShader_SetPermutationGLSL(5, 8388608);
3142         R_SetupShader_SetPermutationGLSL(11, 1);
3143         R_SetupShader_SetPermutationGLSL(11, 2049);
3144         R_SetupShader_SetPermutationGLSL(11, 8193);
3145         R_SetupShader_SetPermutationGLSL(11, 10241);
3146         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3147 #endif
3148 }
3149
3150 extern unsigned int r_shadow_occlusion_buf;
3151
3152 static void gl_main_shutdown(void)
3153 {
3154         R_RenderTarget_FreeUnused(true);
3155         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3156         R_AnimCache_Free();
3157         R_FrameData_Reset();
3158         R_BufferData_Reset();
3159
3160         R_Main_FreeViewCache();
3161
3162         switch(vid.renderpath)
3163         {
3164         case RENDERPATH_GL32:
3165         case RENDERPATH_GLES2:
3166 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3167                 if (r_maxqueries)
3168                         qglDeleteQueries(r_maxqueries, r_queries);
3169 #endif
3170                 break;
3171         }
3172         r_shadow_occlusion_buf = 0;
3173         r_numqueries = 0;
3174         r_maxqueries = 0;
3175         memset(r_queries, 0, sizeof(r_queries));
3176
3177         r_qwskincache = NULL;
3178         r_qwskincache_size = 0;
3179
3180         // clear out the r_skinframe state
3181         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3182         memset(&r_skinframe, 0, sizeof(r_skinframe));
3183
3184         if (r_svbsp.nodes)
3185                 Mem_Free(r_svbsp.nodes);
3186         memset(&r_svbsp, 0, sizeof (r_svbsp));
3187         R_FreeTexturePool(&r_main_texturepool);
3188         loadingscreentexture = NULL;
3189         r_texture_blanknormalmap = NULL;
3190         r_texture_white = NULL;
3191         r_texture_grey128 = NULL;
3192         r_texture_black = NULL;
3193         r_texture_whitecube = NULL;
3194         r_texture_normalizationcube = NULL;
3195         r_texture_fogattenuation = NULL;
3196         r_texture_fogheighttexture = NULL;
3197         r_texture_gammaramps = NULL;
3198         r_texture_numcubemaps = 0;
3199         //r_texture_fogintensity = NULL;
3200         memset(&r_fb, 0, sizeof(r_fb));
3201         R_GLSL_Restart_f(cmd_local);
3202
3203         r_glsl_permutation = NULL;
3204         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3205         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3206 }
3207
3208 static void gl_main_newmap(void)
3209 {
3210         // FIXME: move this code to client
3211         char *entities, entname[MAX_QPATH];
3212         if (r_qwskincache)
3213                 Mem_Free(r_qwskincache);
3214         r_qwskincache = NULL;
3215         r_qwskincache_size = 0;
3216         if (cl.worldmodel)
3217         {
3218                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3219                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3220                 {
3221                         CL_ParseEntityLump(entities);
3222                         Mem_Free(entities);
3223                         return;
3224                 }
3225                 if (cl.worldmodel->brush.entities)
3226                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3227         }
3228         R_Main_FreeViewCache();
3229
3230         R_FrameData_Reset();
3231         R_BufferData_Reset();
3232 }
3233
3234 void GL_Main_Init(void)
3235 {
3236         int i;
3237         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3238         R_InitShaderModeInfo();
3239
3240         Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3241         Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3242         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3243         if (gamemode == GAME_NEHAHRA)
3244         {
3245                 Cvar_RegisterVariable (&gl_fogenable);
3246                 Cvar_RegisterVariable (&gl_fogdensity);
3247                 Cvar_RegisterVariable (&gl_fogred);
3248                 Cvar_RegisterVariable (&gl_foggreen);
3249                 Cvar_RegisterVariable (&gl_fogblue);
3250                 Cvar_RegisterVariable (&gl_fogstart);
3251                 Cvar_RegisterVariable (&gl_fogend);
3252                 Cvar_RegisterVariable (&gl_skyclip);
3253         }
3254         Cvar_RegisterVariable(&r_motionblur);
3255         Cvar_RegisterVariable(&r_damageblur);
3256         Cvar_RegisterVariable(&r_motionblur_averaging);
3257         Cvar_RegisterVariable(&r_motionblur_randomize);
3258         Cvar_RegisterVariable(&r_motionblur_minblur);
3259         Cvar_RegisterVariable(&r_motionblur_maxblur);
3260         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3261         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3262         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3263         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3264         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3265         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3266         Cvar_RegisterVariable(&r_depthfirst);
3267         Cvar_RegisterVariable(&r_useinfinitefarclip);
3268         Cvar_RegisterVariable(&r_farclip_base);
3269         Cvar_RegisterVariable(&r_farclip_world);
3270         Cvar_RegisterVariable(&r_nearclip);
3271         Cvar_RegisterVariable(&r_deformvertexes);
3272         Cvar_RegisterVariable(&r_transparent);
3273         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3274         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3275         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3276         Cvar_RegisterVariable(&r_showoverdraw);
3277         Cvar_RegisterVariable(&r_showbboxes);
3278         Cvar_RegisterVariable(&r_showbboxes_client);
3279         Cvar_RegisterVariable(&r_showsurfaces);
3280         Cvar_RegisterVariable(&r_showtris);
3281         Cvar_RegisterVariable(&r_shownormals);
3282         Cvar_RegisterVariable(&r_showlighting);
3283         Cvar_RegisterVariable(&r_showcollisionbrushes);
3284         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3285         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3286         Cvar_RegisterVariable(&r_showdisabledepthtest);
3287         Cvar_RegisterVariable(&r_showspriteedges);
3288         Cvar_RegisterVariable(&r_showparticleedges);
3289         Cvar_RegisterVariable(&r_drawportals);
3290         Cvar_RegisterVariable(&r_drawentities);
3291         Cvar_RegisterVariable(&r_draw2d);
3292         Cvar_RegisterVariable(&r_drawworld);
3293         Cvar_RegisterVariable(&r_cullentities_trace);
3294         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3295         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3296         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3297         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3298         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3299         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3300         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3301         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3302         Cvar_RegisterVariable(&r_sortentities);
3303         Cvar_RegisterVariable(&r_drawviewmodel);
3304         Cvar_RegisterVariable(&r_drawexteriormodel);
3305         Cvar_RegisterVariable(&r_speeds);
3306         Cvar_RegisterVariable(&r_fullbrights);
3307         Cvar_RegisterVariable(&r_wateralpha);
3308         Cvar_RegisterVariable(&r_dynamic);
3309         Cvar_RegisterVariable(&r_fullbright_directed);
3310         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3311         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3312         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3313         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3314         Cvar_RegisterVariable(&r_fullbright);
3315         Cvar_RegisterVariable(&r_shadows);
3316         Cvar_RegisterVariable(&r_shadows_darken);
3317         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3318         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3319         Cvar_RegisterVariable(&r_shadows_throwdistance);
3320         Cvar_RegisterVariable(&r_shadows_throwdirection);
3321         Cvar_RegisterVariable(&r_shadows_focus);
3322         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3323         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3324         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3325         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3326         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3327         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3328         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3329         Cvar_RegisterVariable(&r_fog_exp2);
3330         Cvar_RegisterVariable(&r_fog_clear);
3331         Cvar_RegisterVariable(&r_drawfog);
3332         Cvar_RegisterVariable(&r_transparentdepthmasking);
3333         Cvar_RegisterVariable(&r_transparent_sortmindist);
3334         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3335         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3336         Cvar_RegisterVariable(&r_texture_dds_load);
3337         Cvar_RegisterVariable(&r_texture_dds_save);
3338         Cvar_RegisterVariable(&r_textureunits);
3339         Cvar_RegisterVariable(&gl_combine);
3340         Cvar_RegisterVariable(&r_usedepthtextures);
3341         Cvar_RegisterVariable(&r_viewfbo);
3342         Cvar_RegisterVariable(&r_rendertarget_debug);
3343         Cvar_RegisterVariable(&r_viewscale);
3344         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3345         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3346         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3347         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3348         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3349         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3350         Cvar_RegisterVariable(&r_glsl);
3351         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3352         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3353         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3354         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3355         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3356         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3357         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3358         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3359         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3360         Cvar_RegisterVariable(&r_glsl_postprocess);
3361         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3362         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3363         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3364         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3365         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3366         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3367         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3368         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3369         Cvar_RegisterVariable(&r_celshading);
3370         Cvar_RegisterVariable(&r_celoutlines);
3371
3372         Cvar_RegisterVariable(&r_water);
3373         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3374         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3375         Cvar_RegisterVariable(&r_water_clippingplanebias);
3376         Cvar_RegisterVariable(&r_water_refractdistort);
3377         Cvar_RegisterVariable(&r_water_reflectdistort);
3378         Cvar_RegisterVariable(&r_water_scissormode);
3379         Cvar_RegisterVariable(&r_water_lowquality);
3380         Cvar_RegisterVariable(&r_water_hideplayer);
3381
3382         Cvar_RegisterVariable(&r_lerpsprites);
3383         Cvar_RegisterVariable(&r_lerpmodels);
3384         Cvar_RegisterVariable(&r_nolerp_list);
3385         Cvar_RegisterVariable(&r_lerplightstyles);
3386         Cvar_RegisterVariable(&r_waterscroll);
3387         Cvar_RegisterVariable(&r_bloom);
3388         Cvar_RegisterVariable(&r_colorfringe);
3389         Cvar_RegisterVariable(&r_bloom_colorscale);
3390         Cvar_RegisterVariable(&r_bloom_brighten);
3391         Cvar_RegisterVariable(&r_bloom_blur);
3392         Cvar_RegisterVariable(&r_bloom_resolution);
3393         Cvar_RegisterVariable(&r_bloom_colorexponent);
3394         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3395         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3396         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3397         Cvar_RegisterVariable(&r_hdr_glowintensity);
3398         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3399         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3400         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3401         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3402         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3403         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3404         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3405         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3406         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3407         Cvar_RegisterVariable(&developer_texturelogging);
3408         Cvar_RegisterVariable(&gl_lightmaps);
3409         Cvar_RegisterVariable(&r_test);
3410         Cvar_RegisterVariable(&r_batch_multidraw);
3411         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3412         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3413         Cvar_RegisterVariable(&r_glsl_skeletal);
3414         Cvar_RegisterVariable(&r_glsl_saturation);
3415         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3416         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3417         Cvar_RegisterVariable(&r_framedatasize);
3418         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3419                 Cvar_RegisterVariable(&r_buffermegs[i]);
3420         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3421         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3422         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3423         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3424         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3425                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3426 #ifdef DP_MOBILETOUCH
3427         // GLES devices have terrible depth precision in general, so...
3428         Cvar_SetValueQuick(&r_nearclip, 4);
3429         Cvar_SetValueQuick(&r_farclip_base, 4096);
3430         Cvar_SetValueQuick(&r_farclip_world, 0);
3431         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3432 #endif
3433         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3434 }
3435
3436 void Render_Init(void)
3437 {
3438         gl_backend_init();
3439         R_Textures_Init();
3440         GL_Main_Init();
3441         Font_Init();
3442         GL_Draw_Init();
3443         R_Shadow_Init();
3444         R_Sky_Init();
3445         GL_Surf_Init();
3446         Sbar_Init();
3447         R_Particles_Init();
3448         R_Explosion_Init();
3449         R_LightningBeams_Init();
3450         CL_MeshEntities_Init();
3451         Mod_RenderInit();
3452 }
3453
3454 static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits)
3455 {
3456         out[0] = ((signbits & 1) ? mins : maxs)[0];
3457         out[1] = ((signbits & 2) ? mins : maxs)[1];
3458         out[2] = ((signbits & 4) ? mins : maxs)[2];
3459 }
3460
3461 static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore)
3462 {
3463         int i;
3464         const mplane_t *p;
3465         vec3_t corner;
3466         if (r_trippy.integer)
3467                 return false;
3468         for (i = 0;i < numplanes;i++)
3469         {
3470                 if(i == ignore)
3471                         continue;
3472                 p = planes + i;
3473                 R_GetCornerOfBox(corner, mins, maxs, p->signbits);
3474                 if (DotProduct(p->normal, corner) < p->dist)
3475                         return true;
3476         }
3477         return false;
3478 }
3479
3480 qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs)
3481 {
3482         // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
3483         return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4);
3484 }
3485
3486 qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3487 {
3488         // nothing to ignore
3489         return _R_CullBox(mins, maxs, numplanes, planes, -1);
3490 }
3491
3492 //==================================================================================
3493
3494 // LadyHavoc: this stores temporary data used within the same frame
3495
3496 typedef struct r_framedata_mem_s
3497 {
3498         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3499         size_t size; // how much usable space
3500         size_t current; // how much space in use
3501         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3502         size_t wantedsize; // how much space was allocated
3503         unsigned char *data; // start of real data (16byte aligned)
3504 }
3505 r_framedata_mem_t;
3506
3507 static r_framedata_mem_t *r_framedata_mem;
3508
3509 void R_FrameData_Reset(void)
3510 {
3511         while (r_framedata_mem)
3512         {
3513                 r_framedata_mem_t *next = r_framedata_mem->purge;
3514                 Mem_Free(r_framedata_mem);
3515                 r_framedata_mem = next;
3516         }
3517 }
3518
3519 static void R_FrameData_Resize(qbool mustgrow)
3520 {
3521         size_t wantedsize;
3522         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3523         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3524         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3525         {
3526                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3527                 newmem->wantedsize = wantedsize;
3528                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3529                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3530                 newmem->current = 0;
3531                 newmem->mark = 0;
3532                 newmem->purge = r_framedata_mem;
3533                 r_framedata_mem = newmem;
3534         }
3535 }
3536
3537 void R_FrameData_NewFrame(void)
3538 {
3539         R_FrameData_Resize(false);
3540         if (!r_framedata_mem)
3541                 return;
3542         // if we ran out of space on the last frame, free the old memory now
3543         while (r_framedata_mem->purge)
3544         {
3545                 // repeatedly remove the second item in the list, leaving only head
3546                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3547                 Mem_Free(r_framedata_mem->purge);
3548                 r_framedata_mem->purge = next;
3549         }
3550         // reset the current mem pointer
3551         r_framedata_mem->current = 0;
3552         r_framedata_mem->mark = 0;
3553 }
3554
3555 void *R_FrameData_Alloc(size_t size)
3556 {
3557         void *data;
3558         float newvalue;
3559
3560         // align to 16 byte boundary - the data pointer is already aligned, so we
3561         // only need to ensure the size of every allocation is also aligned
3562         size = (size + 15) & ~15;
3563
3564         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3565         {
3566                 // emergency - we ran out of space, allocate more memory
3567                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3568                 newvalue = r_framedatasize.value * 2.0f;
3569                 // 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
3570                 if (sizeof(size_t) >= 8)
3571                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3572                 else
3573                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3574                 // this might not be a growing it, but we'll allocate another buffer every time
3575                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3576                 R_FrameData_Resize(true);
3577         }
3578
3579         data = r_framedata_mem->data + r_framedata_mem->current;
3580         r_framedata_mem->current += size;
3581
3582         // count the usage for stats
3583         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3584         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3585
3586         return (void *)data;
3587 }
3588
3589 void *R_FrameData_Store(size_t size, void *data)
3590 {
3591         void *d = R_FrameData_Alloc(size);
3592         if (d && data)
3593                 memcpy(d, data, size);
3594         return d;
3595 }
3596
3597 void R_FrameData_SetMark(void)
3598 {
3599         if (!r_framedata_mem)
3600                 return;
3601         r_framedata_mem->mark = r_framedata_mem->current;
3602 }
3603
3604 void R_FrameData_ReturnToMark(void)
3605 {
3606         if (!r_framedata_mem)
3607                 return;
3608         r_framedata_mem->current = r_framedata_mem->mark;
3609 }
3610
3611 //==================================================================================
3612
3613 // avoid reusing the same buffer objects on consecutive frames
3614 #define R_BUFFERDATA_CYCLE 3
3615
3616 typedef struct r_bufferdata_buffer_s
3617 {
3618         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3619         size_t size; // how much usable space
3620         size_t current; // how much space in use
3621         r_meshbuffer_t *buffer; // the buffer itself
3622 }
3623 r_bufferdata_buffer_t;
3624
3625 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3626 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3627
3628 /// frees all dynamic buffers
3629 void R_BufferData_Reset(void)
3630 {
3631         int cycle, type;
3632         r_bufferdata_buffer_t **p, *mem;
3633         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3634         {
3635                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3636                 {
3637                         // free all buffers
3638                         p = &r_bufferdata_buffer[cycle][type];
3639                         while (*p)
3640                         {
3641                                 mem = *p;
3642                                 *p = (*p)->purge;
3643                                 if (mem->buffer)
3644                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3645                                 Mem_Free(mem);
3646                         }
3647                 }
3648         }
3649 }
3650
3651 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3652 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3653 {
3654         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3655         size_t size;
3656         float newvalue = r_buffermegs[type].value;
3657
3658         // increase the cvar if we have to (but only if we already have a mem)
3659         if (mustgrow && mem)
3660                 newvalue *= 2.0f;
3661         newvalue = bound(0.25f, newvalue, 256.0f);
3662         while (newvalue * 1024*1024 < minsize)
3663                 newvalue *= 2.0f;
3664
3665         // clamp the cvar to valid range
3666         newvalue = bound(0.25f, newvalue, 256.0f);
3667         if (r_buffermegs[type].value != newvalue)
3668                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3669
3670         // calculate size in bytes
3671         size = (size_t)(newvalue * 1024*1024);
3672         size = bound(131072, size, 256*1024*1024);
3673
3674         // allocate a new buffer if the size is different (purge old one later)
3675         // or if we were told we must grow the buffer
3676         if (!mem || mem->size != size || mustgrow)
3677         {
3678                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3679                 mem->size = size;
3680                 mem->current = 0;
3681                 if (type == R_BUFFERDATA_VERTEX)
3682                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3683                 else if (type == R_BUFFERDATA_INDEX16)
3684                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3685                 else if (type == R_BUFFERDATA_INDEX32)
3686                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3687                 else if (type == R_BUFFERDATA_UNIFORM)
3688                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3689                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3690                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3691         }
3692 }
3693
3694 void R_BufferData_NewFrame(void)
3695 {
3696         int type;
3697         r_bufferdata_buffer_t **p, *mem;
3698         // cycle to the next frame's buffers
3699         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3700         // if we ran out of space on the last time we used these buffers, free the old memory now
3701         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3702         {
3703                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3704                 {
3705                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3706                         // free all but the head buffer, this is how we recycle obsolete
3707                         // buffers after they are no longer in use
3708                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3709                         while (*p)
3710                         {
3711                                 mem = *p;
3712                                 *p = (*p)->purge;
3713                                 if (mem->buffer)
3714                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3715                                 Mem_Free(mem);
3716                         }
3717                         // reset the current offset
3718                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3719                 }
3720         }
3721 }
3722
3723 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3724 {
3725         r_bufferdata_buffer_t *mem;
3726         int offset = 0;
3727         int padsize;
3728
3729         *returnbufferoffset = 0;
3730
3731         // align size to a byte boundary appropriate for the buffer type, this
3732         // makes all allocations have aligned start offsets
3733         if (type == R_BUFFERDATA_UNIFORM)
3734                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3735         else
3736                 padsize = (datasize + 15) & ~15;
3737
3738         // if we ran out of space in this buffer we must allocate a new one
3739         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)
3740                 R_BufferData_Resize(type, true, padsize);
3741
3742         // if the resize did not give us enough memory, fail
3743         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)
3744                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3745
3746         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3747         offset = (int)mem->current;
3748         mem->current += padsize;
3749
3750         // upload the data to the buffer at the chosen offset
3751         if (offset == 0)
3752                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3753         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3754
3755         // count the usage for stats
3756         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3757         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3758
3759         // return the buffer offset
3760         *returnbufferoffset = offset;
3761
3762         return mem->buffer;
3763 }
3764
3765 //==================================================================================
3766
3767 // LadyHavoc: animcache originally written by Echon, rewritten since then
3768
3769 /**
3770  * Animation cache prevents re-generating mesh data for an animated model
3771  * multiple times in one frame for lighting, shadowing, reflections, etc.
3772  */
3773
3774 void R_AnimCache_Free(void)
3775 {
3776 }
3777
3778 void R_AnimCache_ClearCache(void)
3779 {
3780         int i;
3781         entity_render_t *ent;
3782
3783         for (i = 0;i < r_refdef.scene.numentities;i++)
3784         {
3785                 ent = r_refdef.scene.entities[i];
3786                 ent->animcache_vertex3f = NULL;
3787                 ent->animcache_vertex3f_vertexbuffer = NULL;
3788                 ent->animcache_vertex3f_bufferoffset = 0;
3789                 ent->animcache_normal3f = NULL;
3790                 ent->animcache_normal3f_vertexbuffer = NULL;
3791                 ent->animcache_normal3f_bufferoffset = 0;
3792                 ent->animcache_svector3f = NULL;
3793                 ent->animcache_svector3f_vertexbuffer = NULL;
3794                 ent->animcache_svector3f_bufferoffset = 0;
3795                 ent->animcache_tvector3f = NULL;
3796                 ent->animcache_tvector3f_vertexbuffer = NULL;
3797                 ent->animcache_tvector3f_bufferoffset = 0;
3798                 ent->animcache_skeletaltransform3x4 = NULL;
3799                 ent->animcache_skeletaltransform3x4buffer = NULL;
3800                 ent->animcache_skeletaltransform3x4offset = 0;
3801                 ent->animcache_skeletaltransform3x4size = 0;
3802         }
3803 }
3804
3805 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3806 {
3807         model_t *model = ent->model;
3808         int numvertices;
3809
3810         // see if this ent is worth caching
3811         if (!model || !model->Draw || !model->AnimateVertices)
3812                 return false;
3813         // nothing to cache if it contains no animations and has no skeleton
3814         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3815                 return false;
3816         // see if it is already cached for gpuskeletal
3817         if (ent->animcache_skeletaltransform3x4)
3818                 return false;
3819         // see if it is already cached as a mesh
3820         if (ent->animcache_vertex3f)
3821         {
3822                 // check if we need to add normals or tangents
3823                 if (ent->animcache_normal3f)
3824                         wantnormals = false;
3825                 if (ent->animcache_svector3f)
3826                         wanttangents = false;
3827                 if (!wantnormals && !wanttangents)
3828                         return false;
3829         }
3830
3831         // check which kind of cache we need to generate
3832         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3833         {
3834                 // cache the skeleton so the vertex shader can use it
3835                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3836                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3837                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3838                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3839                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3840                 // note: this can fail if the buffer is at the grow limit
3841                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3842                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3843         }
3844         else if (ent->animcache_vertex3f)
3845         {
3846                 // mesh was already cached but we may need to add normals/tangents
3847                 // (this only happens with multiple views, reflections, cameras, etc)
3848                 if (wantnormals || wanttangents)
3849                 {
3850                         numvertices = model->surfmesh.num_vertices;
3851                         if (wantnormals)
3852                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3853                         if (wanttangents)
3854                         {
3855                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3856                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3857                         }
3858                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3859                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3860                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3861                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3862                 }
3863         }
3864         else
3865         {
3866                 // generate mesh cache
3867                 numvertices = model->surfmesh.num_vertices;
3868                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3869                 if (wantnormals)
3870                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3871                 if (wanttangents)
3872                 {
3873                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3874                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3875                 }
3876                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3877                 if (wantnormals || wanttangents)
3878                 {
3879                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3880                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3881                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3882                 }
3883                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3884                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3885                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3886         }
3887         return true;
3888 }
3889
3890 void R_AnimCache_CacheVisibleEntities(void)
3891 {
3892         int i;
3893
3894         // TODO: thread this
3895         // NOTE: R_PrepareRTLights() also caches entities
3896
3897         for (i = 0;i < r_refdef.scene.numentities;i++)
3898                 if (r_refdef.viewcache.entityvisible[i])
3899                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3900 }
3901
3902 //==================================================================================
3903
3904 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)
3905 {
3906         long unsigned int i;
3907         int j;
3908         vec3_t eyemins, eyemaxs;
3909         vec3_t boxmins, boxmaxs;
3910         vec3_t padmins, padmaxs;
3911         vec3_t start;
3912         vec3_t end;
3913         model_t *model = r_refdef.scene.worldmodel;
3914         static vec3_t positions[] = {
3915                 { 0.5f, 0.5f, 0.5f },
3916                 { 0.0f, 0.0f, 0.0f },
3917                 { 0.0f, 0.0f, 1.0f },
3918                 { 0.0f, 1.0f, 0.0f },
3919                 { 0.0f, 1.0f, 1.0f },
3920                 { 1.0f, 0.0f, 0.0f },
3921                 { 1.0f, 0.0f, 1.0f },
3922                 { 1.0f, 1.0f, 0.0f },
3923                 { 1.0f, 1.0f, 1.0f },
3924         };
3925
3926         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3927         if (numsamples < 0)
3928                 return true;
3929
3930         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3931         if (!r_refdef.view.usevieworiginculling)
3932                 return true;
3933
3934         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3935                 return true;
3936
3937         // expand the eye box a little
3938         eyemins[0] = eye[0] - eyejitter;
3939         eyemaxs[0] = eye[0] + eyejitter;
3940         eyemins[1] = eye[1] - eyejitter;
3941         eyemaxs[1] = eye[1] + eyejitter;
3942         eyemins[2] = eye[2] - eyejitter;
3943         eyemaxs[2] = eye[2] + eyejitter;
3944         // expand the box a little
3945         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3946         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3947         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3948         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3949         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3950         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3951         // make an even larger box for the acceptable area
3952         padmins[0] = boxmins[0] - pad;
3953         padmaxs[0] = boxmaxs[0] + pad;
3954         padmins[1] = boxmins[1] - pad;
3955         padmaxs[1] = boxmaxs[1] + pad;
3956         padmins[2] = boxmins[2] - pad;
3957         padmaxs[2] = boxmaxs[2] + pad;
3958
3959         // return true if eye overlaps enlarged box
3960         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3961                 return true;
3962
3963         VectorCopy(eye, start);
3964         // try specific positions in the box first - note that these can be cached
3965         if (r_cullentities_trace_entityocclusion.integer)
3966         {
3967                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3968                 {
3969                         trace_t trace;
3970                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3971                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3972                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3973                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3974                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3975                         // not picky - if the trace ended anywhere in the box we're good
3976                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3977                                 return true;
3978                 }
3979         }
3980         else
3981         {
3982                 // try center
3983                 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
3984                 if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3985                         return true;
3986         }
3987
3988         // try various random positions
3989         for (j = 0; j < numsamples; j++)
3990         {
3991                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3992                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3993                 if (r_cullentities_trace_entityocclusion.integer)
3994                 {
3995                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3996                         // not picky - if the trace ended anywhere in the box we're good
3997                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3998                                 return true;
3999                 }
4000                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4001                         return true;
4002         }
4003
4004         return false;
4005 }
4006
4007
4008 static void R_View_UpdateEntityVisible (void)
4009 {
4010         int i;
4011         int renderimask;
4012         int samples;
4013         entity_render_t *ent;
4014
4015         if (r_refdef.envmap || r_fb.water.hideplayer)
4016                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4017         else if (chase_active.integer || r_fb.water.renderingscene)
4018                 renderimask = RENDER_VIEWMODEL;
4019         else
4020                 renderimask = RENDER_EXTERIORMODEL;
4021         if (!r_drawviewmodel.integer)
4022                 renderimask |= RENDER_VIEWMODEL;
4023         if (!r_drawexteriormodel.integer)
4024                 renderimask |= RENDER_EXTERIORMODEL;
4025         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4026         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4027         {
4028                 // worldmodel can check visibility
4029                 for (i = 0;i < r_refdef.scene.numentities;i++)
4030                 {
4031                         ent = r_refdef.scene.entities[i];
4032                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4033                         {
4034                                 r_refdef.viewcache.entityvisible[i] = false;
4035                                 continue;
4036                         }
4037                         if (!(ent->flags & renderimask))
4038                         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)))
4039                         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))
4040                                 r_refdef.viewcache.entityvisible[i] = true;
4041                 }
4042         }
4043         else
4044         {
4045                 // no worldmodel or it can't check visibility
4046                 for (i = 0;i < r_refdef.scene.numentities;i++)
4047                 {
4048                         ent = r_refdef.scene.entities[i];
4049                         if (!(ent->flags & renderimask))
4050                         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)))
4051                                 r_refdef.viewcache.entityvisible[i] = true;
4052                 }
4053         }
4054         if (r_cullentities_trace.integer)
4055         {
4056                 for (i = 0;i < r_refdef.scene.numentities;i++)
4057                 {
4058                         if (!r_refdef.viewcache.entityvisible[i])
4059                                 continue;
4060                         ent = r_refdef.scene.entities[i];
4061                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4062                         {
4063                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4064                                 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))
4065                                         ent->last_trace_visibility = host.realtime;
4066                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4067                                         r_refdef.viewcache.entityvisible[i] = 0;
4068                         }
4069                 }
4070         }
4071 }
4072
4073 /// only used if skyrendermasked, and normally returns false
4074 static int R_DrawBrushModelsSky (void)
4075 {
4076         int i, sky;
4077         entity_render_t *ent;
4078
4079         sky = false;
4080         for (i = 0;i < r_refdef.scene.numentities;i++)
4081         {
4082                 if (!r_refdef.viewcache.entityvisible[i])
4083                         continue;
4084                 ent = r_refdef.scene.entities[i];
4085                 if (!ent->model || !ent->model->DrawSky)
4086                         continue;
4087                 ent->model->DrawSky(ent);
4088                 sky = true;
4089         }
4090         return sky;
4091 }
4092
4093 static void R_DrawNoModel(entity_render_t *ent);
4094 static void R_DrawModels(void)
4095 {
4096         int i;
4097         entity_render_t *ent;
4098
4099         for (i = 0;i < r_refdef.scene.numentities;i++)
4100         {
4101                 if (!r_refdef.viewcache.entityvisible[i])
4102                         continue;
4103                 ent = r_refdef.scene.entities[i];
4104                 r_refdef.stats[r_stat_entities]++;
4105
4106                 if (ent->model && ent->model->Draw != NULL)
4107                         ent->model->Draw(ent);
4108                 else
4109                         R_DrawNoModel(ent);
4110         }
4111 }
4112
4113 static void R_DrawModelsDepth(void)
4114 {
4115         int i;
4116         entity_render_t *ent;
4117
4118         for (i = 0;i < r_refdef.scene.numentities;i++)
4119         {
4120                 if (!r_refdef.viewcache.entityvisible[i])
4121                         continue;
4122                 ent = r_refdef.scene.entities[i];
4123                 if (ent->model && ent->model->DrawDepth != NULL)
4124                         ent->model->DrawDepth(ent);
4125         }
4126 }
4127
4128 static void R_DrawModelsDebug(void)
4129 {
4130         int i;
4131         entity_render_t *ent;
4132
4133         for (i = 0;i < r_refdef.scene.numentities;i++)
4134         {
4135                 if (!r_refdef.viewcache.entityvisible[i])
4136                         continue;
4137                 ent = r_refdef.scene.entities[i];
4138                 if (ent->model && ent->model->DrawDebug != NULL)
4139                         ent->model->DrawDebug(ent);
4140         }
4141 }
4142
4143 static void R_DrawModelsAddWaterPlanes(void)
4144 {
4145         int i;
4146         entity_render_t *ent;
4147
4148         for (i = 0;i < r_refdef.scene.numentities;i++)
4149         {
4150                 if (!r_refdef.viewcache.entityvisible[i])
4151                         continue;
4152                 ent = r_refdef.scene.entities[i];
4153                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4154                         ent->model->DrawAddWaterPlanes(ent);
4155         }
4156 }
4157
4158 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}};
4159
4160 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4161 {
4162         if (r_hdr_irisadaptation.integer)
4163         {
4164                 vec3_t p;
4165                 vec3_t ambient;
4166                 vec3_t diffuse;
4167                 vec3_t diffusenormal;
4168                 vec3_t forward;
4169                 vec_t brightness = 0.0f;
4170                 vec_t goal;
4171                 vec_t current;
4172                 vec_t d;
4173                 int c;
4174                 VectorCopy(r_refdef.view.forward, forward);
4175                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4176                 {
4177                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4178                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4179                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4180                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4181                         d = DotProduct(forward, diffusenormal);
4182                         brightness += VectorLength(ambient);
4183                         if (d > 0)
4184                                 brightness += d * VectorLength(diffuse);
4185                 }
4186                 brightness *= 1.0f / c;
4187                 brightness += 0.00001f; // make sure it's never zero
4188                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4189                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4190                 current = r_hdr_irisadaptation_value.value;
4191                 if (current < goal)
4192                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4193                 else if (current > goal)
4194                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4195                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4196                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4197         }
4198         else if (r_hdr_irisadaptation_value.value != 1.0f)
4199                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4200 }
4201
4202 extern cvar_t r_lockvisibility;
4203 extern cvar_t r_lockpvs;
4204
4205 static void R_View_SetFrustum(const int *scissor)
4206 {
4207         int i;
4208         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4209         vec3_t forward, left, up, origin, v;
4210         if(r_lockvisibility.integer)
4211                 return;
4212         if(scissor)
4213         {
4214                 // flipped x coordinates (because x points left here)
4215                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4216                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4217                 // non-flipped y coordinates
4218                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4219                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4220         }
4221
4222         // we can't trust r_refdef.view.forward and friends in reflected scenes
4223         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4224
4225 #if 0
4226         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4227         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4228         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4229         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4230         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4231         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4232         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4233         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4234         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4235         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4236         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4237         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4238 #endif
4239
4240 #if 0
4241         zNear = r_refdef.nearclip;
4242         nudge = 1.0 - 1.0 / (1<<23);
4243         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4244         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4245         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4246         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4247         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4248         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4249         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4250         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4251 #endif
4252
4253
4254
4255 #if 0
4256         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4257         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4258         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4259         r_refdef.view.frustum[0].dist = m[15] - m[12];
4260
4261         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4262         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4263         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4264         r_refdef.view.frustum[1].dist = m[15] + m[12];
4265
4266         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4267         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4268         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4269         r_refdef.view.frustum[2].dist = m[15] - m[13];
4270
4271         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4272         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4273         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4274         r_refdef.view.frustum[3].dist = m[15] + m[13];
4275
4276         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4277         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4278         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4279         r_refdef.view.frustum[4].dist = m[15] - m[14];
4280
4281         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4282         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4283         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4284         r_refdef.view.frustum[5].dist = m[15] + m[14];
4285 #endif
4286
4287         if (r_refdef.view.useperspective)
4288         {
4289                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4290                 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]);
4291                 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]);
4292                 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]);
4293                 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]);
4294
4295                 // then the normals from the corners relative to origin
4296                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4297                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4298                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4299                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4300
4301                 // in a NORMAL view, forward cross left == up
4302                 // in a REFLECTED view, forward cross left == down
4303                 // so our cross products above need to be adjusted for a left handed coordinate system
4304                 CrossProduct(forward, left, v);
4305                 if(DotProduct(v, up) < 0)
4306                 {
4307                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4308                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4309                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4310                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4311                 }
4312
4313                 // Leaving those out was a mistake, those were in the old code, and they
4314                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4315                 // I couldn't reproduce it after adding those normalizations. --blub
4316                 VectorNormalize(r_refdef.view.frustum[0].normal);
4317                 VectorNormalize(r_refdef.view.frustum[1].normal);
4318                 VectorNormalize(r_refdef.view.frustum[2].normal);
4319                 VectorNormalize(r_refdef.view.frustum[3].normal);
4320
4321                 // make the corners absolute
4322                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4323                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4324                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4325                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4326
4327                 // one more normal
4328                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4329
4330                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4331                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4332                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4333                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4334                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4335         }
4336         else
4337         {
4338                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4339                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4340                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4341                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4342                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4343                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4344                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4345                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4346                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4347                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4348         }
4349         r_refdef.view.numfrustumplanes = 5;
4350
4351         if (r_refdef.view.useclipplane)
4352         {
4353                 r_refdef.view.numfrustumplanes = 6;
4354                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4355         }
4356
4357         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4358                 PlaneClassify(r_refdef.view.frustum + i);
4359
4360         // LadyHavoc: note to all quake engine coders, Quake had a special case
4361         // for 90 degrees which assumed a square view (wrong), so I removed it,
4362         // Quake2 has it disabled as well.
4363
4364         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4365         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4366         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4367         //PlaneClassify(&frustum[0]);
4368
4369         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4370         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4371         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4372         //PlaneClassify(&frustum[1]);
4373
4374         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4375         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4376         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4377         //PlaneClassify(&frustum[2]);
4378
4379         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4380         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4381         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4382         //PlaneClassify(&frustum[3]);
4383
4384         // nearclip plane
4385         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4386         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4387         //PlaneClassify(&frustum[4]);
4388 }
4389
4390 static void R_View_UpdateWithScissor(const int *myscissor)
4391 {
4392         R_Main_ResizeViewCache();
4393         R_View_SetFrustum(myscissor);
4394         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4395         R_View_UpdateEntityVisible();
4396 }
4397
4398 static void R_View_Update(void)
4399 {
4400         R_Main_ResizeViewCache();
4401         R_View_SetFrustum(NULL);
4402         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4403         R_View_UpdateEntityVisible();
4404 }
4405
4406 float viewscalefpsadjusted = 1.0f;
4407
4408 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4409 {
4410         const float *customclipplane = NULL;
4411         float plane[4];
4412         int /*rtwidth,*/ rtheight;
4413         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4414         {
4415                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4416                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4417                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4418                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4419                         dist = r_refdef.view.clipplane.dist;
4420                 plane[0] = r_refdef.view.clipplane.normal[0];
4421                 plane[1] = r_refdef.view.clipplane.normal[1];
4422                 plane[2] = r_refdef.view.clipplane.normal[2];
4423                 plane[3] = -dist;
4424                 customclipplane = plane;
4425         }
4426
4427         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4428         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4429
4430         if (!r_refdef.view.useperspective)
4431                 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);
4432         else if (vid.stencil && r_useinfinitefarclip.integer)
4433                 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);
4434         else
4435                 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);
4436         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4437         R_SetViewport(&r_refdef.view.viewport);
4438 }
4439
4440 void R_EntityMatrix(const matrix4x4_t *matrix)
4441 {
4442         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4443         {
4444                 gl_modelmatrixchanged = false;
4445                 gl_modelmatrix = *matrix;
4446                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4447                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4448                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4449                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4450                 CHECKGLERROR
4451                 switch(vid.renderpath)
4452                 {
4453                 case RENDERPATH_GL32:
4454                 case RENDERPATH_GLES2:
4455                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4456                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4457                         break;
4458                 }
4459         }
4460 }
4461
4462 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4463 {
4464         r_viewport_t viewport;
4465
4466         CHECKGLERROR
4467
4468         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4469         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4470         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4471         R_SetViewport(&viewport);
4472         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4473         GL_Color(1, 1, 1, 1);
4474         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4475         GL_BlendFunc(GL_ONE, GL_ZERO);
4476         GL_ScissorTest(false);
4477         GL_DepthMask(false);
4478         GL_DepthRange(0, 1);
4479         GL_DepthTest(false);
4480         GL_DepthFunc(GL_LEQUAL);
4481         R_EntityMatrix(&identitymatrix);
4482         R_Mesh_ResetTextureState();
4483         GL_PolygonOffset(0, 0);
4484         switch(vid.renderpath)
4485         {
4486         case RENDERPATH_GL32:
4487         case RENDERPATH_GLES2:
4488                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4489                 break;
4490         }
4491         GL_CullFace(GL_NONE);
4492
4493         CHECKGLERROR
4494 }
4495
4496 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4497 {
4498         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4499 }
4500
4501 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4502 {
4503         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4504         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4505         GL_Color(1, 1, 1, 1);
4506         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4507         GL_BlendFunc(GL_ONE, GL_ZERO);
4508         GL_ScissorTest(true);
4509         GL_DepthMask(true);
4510         GL_DepthRange(0, 1);
4511         GL_DepthTest(true);
4512         GL_DepthFunc(GL_LEQUAL);
4513         R_EntityMatrix(&identitymatrix);
4514         R_Mesh_ResetTextureState();
4515         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4516         switch(vid.renderpath)
4517         {
4518         case RENDERPATH_GL32:
4519         case RENDERPATH_GLES2:
4520                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4521                 break;
4522         }
4523         GL_CullFace(r_refdef.view.cullface_back);
4524 }
4525
4526 /*
4527 ================
4528 R_RenderView_UpdateViewVectors
4529 ================
4530 */
4531 void R_RenderView_UpdateViewVectors(void)
4532 {
4533         // break apart the view matrix into vectors for various purposes
4534         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4535         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4536         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4537         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4538         // make an inverted copy of the view matrix for tracking sprites
4539         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4540 }
4541
4542 void R_RenderTarget_FreeUnused(qbool force)
4543 {
4544         unsigned int i, j, end;
4545         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4546         for (i = 0; i < end; i++)
4547         {
4548                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4549                 // free resources for rendertargets that have not been used for a while
4550                 // (note: this check is run after the frame render, so any targets used
4551                 // this frame will not be affected even at low framerates)
4552                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4553                 {
4554                         if (r->fbo)
4555                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4556                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4557                                 if (r->colortexture[j])
4558                                         R_FreeTexture(r->colortexture[j]);
4559                         if (r->depthtexture)
4560                                 R_FreeTexture(r->depthtexture);
4561                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4562                 }
4563         }
4564 }
4565
4566 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4567 {
4568         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4569         x1 = x * iw;
4570         x2 = (x + w) * iw;
4571         y1 = (th - y) * ih;
4572         y2 = (th - y - h) * ih;
4573         texcoord2f[0] = x1;
4574         texcoord2f[2] = x2;
4575         texcoord2f[4] = x2;
4576         texcoord2f[6] = x1;
4577         texcoord2f[1] = y1;
4578         texcoord2f[3] = y1;
4579         texcoord2f[5] = y2;
4580         texcoord2f[7] = y2;
4581 }
4582
4583 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)
4584 {
4585         unsigned int i, j, end;
4586         r_rendertarget_t *r = NULL;
4587         char vabuf[256];
4588         // first try to reuse an existing slot if possible
4589         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4590         for (i = 0; i < end; i++)
4591         {
4592                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4593                 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)
4594                         break;
4595         }
4596         if (i == end)
4597         {
4598                 // no unused exact match found, so we have to make one in the first unused slot
4599                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4600                 r->texturewidth = texturewidth;
4601                 r->textureheight = textureheight;
4602                 r->colortextype[0] = colortextype0;
4603                 r->colortextype[1] = colortextype1;
4604                 r->colortextype[2] = colortextype2;
4605                 r->colortextype[3] = colortextype3;
4606                 r->depthtextype = depthtextype;
4607                 r->depthisrenderbuffer = depthisrenderbuffer;
4608                 for (j = 0; j < 4; j++)
4609                         if (r->colortextype[j])
4610                                 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);
4611                 if (r->depthtextype)
4612                 {
4613                         if (r->depthisrenderbuffer)
4614                                 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);
4615                         else
4616                                 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);
4617                 }
4618                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4619         }
4620         r_refdef.stats[r_stat_rendertargets_used]++;
4621         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4622         r->lastusetime = host.realtime;
4623         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4624         return r;
4625 }
4626
4627 static void R_Water_StartFrame(int viewwidth, int viewheight)
4628 {
4629         int waterwidth, waterheight;
4630
4631         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4632                 return;
4633
4634         // set waterwidth and waterheight to the water resolution that will be
4635         // used (often less than the screen resolution for faster rendering)
4636         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4637         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4638
4639         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4640                 waterwidth = waterheight = 0;
4641
4642         // set up variables that will be used in shader setup
4643         r_fb.water.waterwidth = waterwidth;
4644         r_fb.water.waterheight = waterheight;
4645         r_fb.water.texturewidth = waterwidth;
4646         r_fb.water.textureheight = waterheight;
4647         r_fb.water.camerawidth = waterwidth;
4648         r_fb.water.cameraheight = waterheight;
4649         r_fb.water.screenscale[0] = 0.5f;
4650         r_fb.water.screenscale[1] = 0.5f;
4651         r_fb.water.screencenter[0] = 0.5f;
4652         r_fb.water.screencenter[1] = 0.5f;
4653         r_fb.water.enabled = waterwidth != 0;
4654
4655         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4656         r_fb.water.numwaterplanes = 0;
4657 }
4658
4659 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4660 {
4661         int planeindex, bestplaneindex, vertexindex;
4662         vec3_t mins, maxs, normal, center, v, n;
4663         vec_t planescore, bestplanescore;
4664         mplane_t plane;
4665         r_waterstate_waterplane_t *p;
4666         texture_t *t = R_GetCurrentTexture(surface->texture);
4667
4668         rsurface.texture = t;
4669         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4670         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4671         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4672                 return;
4673         // average the vertex normals, find the surface bounds (after deformvertexes)
4674         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4675         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4676         VectorCopy(n, normal);
4677         VectorCopy(v, mins);
4678         VectorCopy(v, maxs);
4679         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4680         {
4681                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4682                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4683                 VectorAdd(normal, n, normal);
4684                 mins[0] = min(mins[0], v[0]);
4685                 mins[1] = min(mins[1], v[1]);
4686                 mins[2] = min(mins[2], v[2]);
4687                 maxs[0] = max(maxs[0], v[0]);
4688                 maxs[1] = max(maxs[1], v[1]);
4689                 maxs[2] = max(maxs[2], v[2]);
4690         }
4691         VectorNormalize(normal);
4692         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4693
4694         VectorCopy(normal, plane.normal);
4695         VectorNormalize(plane.normal);
4696         plane.dist = DotProduct(center, plane.normal);
4697         PlaneClassify(&plane);
4698         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4699         {
4700                 // skip backfaces (except if nocullface is set)
4701 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4702 //                      return;
4703                 VectorNegate(plane.normal, plane.normal);
4704                 plane.dist *= -1;
4705                 PlaneClassify(&plane);
4706         }
4707
4708
4709         // find a matching plane if there is one
4710         bestplaneindex = -1;
4711         bestplanescore = 1048576.0f;
4712         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4713         {
4714                 if(p->camera_entity == t->camera_entity)
4715                 {
4716                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4717                         if (bestplaneindex < 0 || bestplanescore > planescore)
4718                         {
4719                                 bestplaneindex = planeindex;
4720                                 bestplanescore = planescore;
4721                         }
4722                 }
4723         }
4724         planeindex = bestplaneindex;
4725
4726         // if this surface does not fit any known plane rendered this frame, add one
4727         if (planeindex < 0 || bestplanescore > 0.001f)
4728         {
4729                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4730                 {
4731                         // store the new plane
4732                         planeindex = r_fb.water.numwaterplanes++;
4733                         p = r_fb.water.waterplanes + planeindex;
4734                         p->plane = plane;
4735                         // clear materialflags and pvs
4736                         p->materialflags = 0;
4737                         p->pvsvalid = false;
4738                         p->camera_entity = t->camera_entity;
4739                         VectorCopy(mins, p->mins);
4740                         VectorCopy(maxs, p->maxs);
4741                 }
4742                 else
4743                 {
4744                         // We're totally screwed.
4745                         return;
4746                 }
4747         }
4748         else
4749         {
4750                 // merge mins/maxs when we're adding this surface to the plane
4751                 p = r_fb.water.waterplanes + planeindex;
4752                 p->mins[0] = min(p->mins[0], mins[0]);
4753                 p->mins[1] = min(p->mins[1], mins[1]);
4754                 p->mins[2] = min(p->mins[2], mins[2]);
4755                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4756                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4757                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4758         }
4759         // merge this surface's materialflags into the waterplane
4760         p->materialflags |= t->currentmaterialflags;
4761         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4762         {
4763                 // merge this surface's PVS into the waterplane
4764                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4765                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4766                 {
4767                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4768                         p->pvsvalid = true;
4769                 }
4770         }
4771 }
4772
4773 extern cvar_t r_drawparticles;
4774 extern cvar_t r_drawdecals;
4775
4776 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4777 {
4778         int myscissor[4];
4779         r_refdef_view_t originalview;
4780         r_refdef_view_t myview;
4781         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;
4782         r_waterstate_waterplane_t *p;
4783         vec3_t visorigin;
4784         r_rendertarget_t *rt;
4785
4786         originalview = r_refdef.view;
4787
4788         // lowquality hack, temporarily shut down some cvars and restore afterwards
4789         qualityreduction = r_water_lowquality.integer;
4790         if (qualityreduction > 0)
4791         {
4792                 if (qualityreduction >= 1)
4793                 {
4794                         old_r_shadows = r_shadows.integer;
4795                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4796                         old_r_dlight = r_shadow_realtime_dlight.integer;
4797                         Cvar_SetValueQuick(&r_shadows, 0);
4798                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4799                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4800                 }
4801                 if (qualityreduction >= 2)
4802                 {
4803                         old_r_dynamic = r_dynamic.integer;
4804                         old_r_particles = r_drawparticles.integer;
4805                         old_r_decals = r_drawdecals.integer;
4806                         Cvar_SetValueQuick(&r_dynamic, 0);
4807                         Cvar_SetValueQuick(&r_drawparticles, 0);
4808                         Cvar_SetValueQuick(&r_drawdecals, 0);
4809                 }
4810         }
4811
4812         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4813         {
4814                 p->rt_reflection = NULL;
4815                 p->rt_refraction = NULL;
4816                 p->rt_camera = NULL;
4817         }
4818
4819         // render views
4820         r_refdef.view = originalview;
4821         r_refdef.view.showdebug = false;
4822         r_refdef.view.width = r_fb.water.waterwidth;
4823         r_refdef.view.height = r_fb.water.waterheight;
4824         r_refdef.view.useclipplane = true;
4825         myview = r_refdef.view;
4826         r_fb.water.renderingscene = true;
4827         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4828         {
4829                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4830                         continue;
4831
4832                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4833                 {
4834                         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);
4835                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4836                                 goto error;
4837                         r_refdef.view = myview;
4838                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4839                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4840                         if(r_water_scissormode.integer)
4841                         {
4842                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4843                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4844                                 {
4845                                         p->rt_reflection = NULL;
4846                                         p->rt_refraction = NULL;
4847                                         p->rt_camera = NULL;
4848                                         continue;
4849                                 }
4850                         }
4851
4852                         r_refdef.view.clipplane = p->plane;
4853                         // reflected view origin may be in solid, so don't cull with it
4854                         r_refdef.view.usevieworiginculling = false;
4855                         // reverse the cullface settings for this render
4856                         r_refdef.view.cullface_front = GL_FRONT;
4857                         r_refdef.view.cullface_back = GL_BACK;
4858                         // combined pvs (based on what can be seen from each surface center)
4859                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4860                         {
4861                                 r_refdef.view.usecustompvs = true;
4862                                 if (p->pvsvalid)
4863                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4864                                 else
4865                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4866                         }
4867
4868                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4869                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4870                         GL_ScissorTest(false);
4871                         R_ClearScreen(r_refdef.fogenabled);
4872                         GL_ScissorTest(true);
4873                         if(r_water_scissormode.integer & 2)
4874                                 R_View_UpdateWithScissor(myscissor);
4875                         else
4876                                 R_View_Update();
4877                         R_AnimCache_CacheVisibleEntities();
4878                         if(r_water_scissormode.integer & 1)
4879                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4880                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4881
4882                         r_fb.water.hideplayer = false;
4883                         p->rt_reflection = rt;
4884                 }
4885
4886                 // render the normal view scene and copy into texture
4887                 // (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)
4888                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4889                 {
4890                         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);
4891                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4892                                 goto error;
4893                         r_refdef.view = myview;
4894                         if(r_water_scissormode.integer)
4895                         {
4896                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4897                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4898                                 {
4899                                         p->rt_reflection = NULL;
4900                                         p->rt_refraction = NULL;
4901                                         p->rt_camera = NULL;
4902                                         continue;
4903                                 }
4904                         }
4905
4906                         // combined pvs (based on what can be seen from each surface center)
4907                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4908                         {
4909                                 r_refdef.view.usecustompvs = true;
4910                                 if (p->pvsvalid)
4911                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4912                                 else
4913                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4914                         }
4915
4916                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4917
4918                         r_refdef.view.clipplane = p->plane;
4919                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4920                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4921
4922                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4923                         {
4924                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4925                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4926                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4927                                 R_RenderView_UpdateViewVectors();
4928                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4929                                 {
4930                                         r_refdef.view.usecustompvs = true;
4931                                         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);
4932                                 }
4933                         }
4934
4935                         PlaneClassify(&r_refdef.view.clipplane);
4936
4937                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4938                         GL_ScissorTest(false);
4939                         R_ClearScreen(r_refdef.fogenabled);
4940                         GL_ScissorTest(true);
4941                         if(r_water_scissormode.integer & 2)
4942                                 R_View_UpdateWithScissor(myscissor);
4943                         else
4944                                 R_View_Update();
4945                         R_AnimCache_CacheVisibleEntities();
4946                         if(r_water_scissormode.integer & 1)
4947                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4948                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4949
4950                         r_fb.water.hideplayer = false;
4951                         p->rt_refraction = rt;
4952                 }
4953                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4954                 {
4955                         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);
4956                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4957                                 goto error;
4958                         r_refdef.view = myview;
4959
4960                         r_refdef.view.clipplane = p->plane;
4961                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4962                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4963
4964                         r_refdef.view.width = r_fb.water.camerawidth;
4965                         r_refdef.view.height = r_fb.water.cameraheight;
4966                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4967                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4968                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4969                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4970
4971                         if(p->camera_entity)
4972                         {
4973                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4974                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4975                         }
4976
4977                         // note: all of the view is used for displaying... so
4978                         // there is no use in scissoring
4979
4980                         // reverse the cullface settings for this render
4981                         r_refdef.view.cullface_front = GL_FRONT;
4982                         r_refdef.view.cullface_back = GL_BACK;
4983                         // also reverse the view matrix
4984                         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
4985                         R_RenderView_UpdateViewVectors();
4986                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4987                         {
4988                                 r_refdef.view.usecustompvs = true;
4989                                 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);
4990                         }
4991                         
4992                         // camera needs no clipplane
4993                         r_refdef.view.useclipplane = false;
4994                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4995                         r_refdef.view.usevieworiginculling = false;
4996
4997                         PlaneClassify(&r_refdef.view.clipplane);
4998
4999                         r_fb.water.hideplayer = false;
5000
5001                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5002                         GL_ScissorTest(false);
5003                         R_ClearScreen(r_refdef.fogenabled);
5004                         GL_ScissorTest(true);
5005                         R_View_Update();
5006                         R_AnimCache_CacheVisibleEntities();
5007                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5008
5009                         r_fb.water.hideplayer = false;
5010                         p->rt_camera = rt;
5011                 }
5012
5013         }
5014         r_fb.water.renderingscene = false;
5015         r_refdef.view = originalview;
5016         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5017         R_View_Update();
5018         R_AnimCache_CacheVisibleEntities();
5019         goto finish;
5020 error:
5021         r_refdef.view = originalview;
5022         r_fb.water.renderingscene = false;
5023         Cvar_SetValueQuick(&r_water, 0);
5024         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5025 finish:
5026         // lowquality hack, restore cvars
5027         if (qualityreduction > 0)
5028         {
5029                 if (qualityreduction >= 1)
5030                 {
5031                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5032                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5033                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5034                 }
5035                 if (qualityreduction >= 2)
5036                 {
5037                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5038                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5039                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5040                 }
5041         }
5042 }
5043
5044 static void R_Bloom_StartFrame(void)
5045 {
5046         int screentexturewidth, screentextureheight;
5047         textype_t textype = TEXTYPE_COLORBUFFER;
5048         double scale;
5049
5050         // clear the pointers to rendertargets from last frame as they're stale
5051         r_fb.rt_screen = NULL;
5052         r_fb.rt_bloom = NULL;
5053
5054         switch (vid.renderpath)
5055         {
5056         case RENDERPATH_GL32:
5057                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5058                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5059                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5060                 break;
5061         case RENDERPATH_GLES2:
5062                 r_fb.usedepthtextures = false;
5063                 break;
5064         }
5065
5066         if (r_viewscale_fpsscaling.integer)
5067         {
5068                 double actualframetime;
5069                 double targetframetime;
5070                 double adjust;
5071                 actualframetime = r_refdef.lastdrawscreentime;
5072                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5073                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5074                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5075                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5076                 {
5077                         if (adjust > 0)
5078                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5079                         else
5080                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5081                 }
5082                 viewscalefpsadjusted += adjust;
5083                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5084         }
5085         else
5086                 viewscalefpsadjusted = 1.0f;
5087
5088         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5089         if (vid.samples)
5090                 scale *= sqrt(vid.samples); // supersampling
5091         scale = bound(0.03125f, scale, 4.0f);
5092         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5093         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5094         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5095         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5096
5097         // set bloomwidth and bloomheight to the bloom resolution that will be
5098         // used (often less than the screen resolution for faster rendering)
5099         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5100         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5101         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5102         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5103         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5104
5105         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))
5106         {
5107                 Cvar_SetValueQuick(&r_bloom, 0);
5108                 Cvar_SetValueQuick(&r_motionblur, 0);
5109                 Cvar_SetValueQuick(&r_damageblur, 0);
5110         }
5111         if (!r_bloom.integer)
5112                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5113
5114         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5115         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5116         {
5117                 if (r_fb.ghosttexture)
5118                         R_FreeTexture(r_fb.ghosttexture);
5119                 r_fb.ghosttexture = NULL;
5120
5121                 r_fb.screentexturewidth = screentexturewidth;
5122                 r_fb.screentextureheight = screentextureheight;
5123                 r_fb.textype = textype;
5124
5125                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5126                 {
5127                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5128                                 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);
5129                         r_fb.ghosttexture_valid = false;
5130                 }
5131         }
5132
5133         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5134
5135         r_refdef.view.clear = true;
5136 }
5137
5138 static void R_Bloom_MakeTexture(void)
5139 {
5140         int x, range, dir;
5141         float xoffset, yoffset, r, brighten;
5142         float colorscale = r_bloom_colorscale.value;
5143         r_viewport_t bloomviewport;
5144         r_rendertarget_t *prev, *cur;
5145         textype_t textype = r_fb.rt_screen->colortextype[0];
5146
5147         r_refdef.stats[r_stat_bloom]++;
5148
5149         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5150
5151         // scale down screen texture to the bloom texture size
5152         CHECKGLERROR
5153         prev = r_fb.rt_screen;
5154         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5155         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5156         R_SetViewport(&bloomviewport);
5157         GL_CullFace(GL_NONE);
5158         GL_DepthTest(false);
5159         GL_BlendFunc(GL_ONE, GL_ZERO);
5160         GL_Color(colorscale, colorscale, colorscale, 1);
5161         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5162         // TODO: do boxfilter scale-down in shader?
5163         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5164         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5165         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5166         // we now have a properly scaled bloom image
5167
5168         // multiply bloom image by itself as many times as desired to darken it
5169         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5170         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5171         {
5172                 prev = cur;
5173                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5174                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5175                 x *= 2;
5176                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5177                 if(x <= 2)
5178                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5179                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5180                 GL_Color(1,1,1,1); // no fix factor supported here
5181                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5182                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5183                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5184                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5185         }
5186         CHECKGLERROR
5187
5188         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5189         brighten = r_bloom_brighten.value;
5190         brighten = sqrt(brighten);
5191         if(range >= 1)
5192                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5193
5194         for (dir = 0;dir < 2;dir++)
5195         {
5196                 prev = cur;
5197                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5198                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5199                 // blend on at multiple vertical offsets to achieve a vertical blur
5200                 // TODO: do offset blends using GLSL
5201                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5202                 CHECKGLERROR
5203                 GL_BlendFunc(GL_ONE, GL_ZERO);
5204                 CHECKGLERROR
5205                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5206                 CHECKGLERROR
5207                 for (x = -range;x <= range;x++)
5208                 {
5209                         if (!dir){xoffset = 0;yoffset = x;}
5210                         else {xoffset = x;yoffset = 0;}
5211                         xoffset /= (float)prev->texturewidth;
5212                         yoffset /= (float)prev->textureheight;
5213                         // compute a texcoord array with the specified x and y offset
5214                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5215                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5216                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5217                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5218                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5219                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5220                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5221                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5222                         // this r value looks like a 'dot' particle, fading sharply to
5223                         // black at the edges
5224                         // (probably not realistic but looks good enough)
5225                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5226                         //r = brighten/(range*2+1);
5227                         r = brighten / (range * 2 + 1);
5228                         if(range >= 1)
5229                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5230                         if (r <= 0)
5231                                 continue;
5232                         CHECKGLERROR
5233                         GL_Color(r, r, r, 1);
5234                         CHECKGLERROR
5235                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5236                         CHECKGLERROR
5237                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5238                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5239                         CHECKGLERROR
5240                         GL_BlendFunc(GL_ONE, GL_ONE);
5241                         CHECKGLERROR
5242                 }
5243         }
5244
5245         // now we have the bloom image, so keep track of it
5246         r_fb.rt_bloom = cur;
5247 }
5248
5249 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5250 {
5251         uint64_t permutation;
5252         float uservecs[4][4];
5253         rtexture_t *viewtexture;
5254         rtexture_t *bloomtexture;
5255
5256         R_EntityMatrix(&identitymatrix);
5257
5258         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5259         {
5260                 // declare variables
5261                 float blur_factor, blur_mouseaccel, blur_velocity;
5262                 static float blur_average; 
5263                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5264
5265                 // set a goal for the factoring
5266                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5267                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5268                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5269                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5270                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5271                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5272
5273                 // from the goal, pick an averaged value between goal and last value
5274                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5275                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5276
5277                 // enforce minimum amount of blur 
5278                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5279
5280                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5281
5282                 // calculate values into a standard alpha
5283                 cl.motionbluralpha = 1 - exp(-
5284                                 (
5285                                         (r_motionblur.value * blur_factor / 80)
5286                                         +
5287                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5288                                 )
5289                                 /
5290                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5291                                 );
5292
5293                 // randomization for the blur value to combat persistent ghosting
5294                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5295                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5296
5297                 // apply the blur
5298                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5299                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5300                 {
5301                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5302                         GL_Color(1, 1, 1, cl.motionbluralpha);
5303                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5304                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5305                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5306                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5307                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5308                 }
5309
5310                 // updates old view angles for next pass
5311                 VectorCopy(cl.viewangles, blur_oldangles);
5312
5313                 // copy view into the ghost texture
5314                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5315                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5316                 r_fb.ghosttexture_valid = true;
5317         }
5318
5319         if (r_fb.bloomwidth)
5320         {
5321                 // make the bloom texture
5322                 R_Bloom_MakeTexture();
5323         }
5324
5325 #if _MSC_VER >= 1400
5326 #define sscanf sscanf_s
5327 #endif
5328         memset(uservecs, 0, sizeof(uservecs));
5329         if (r_glsl_postprocess_uservec1_enable.integer)
5330                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5331         if (r_glsl_postprocess_uservec2_enable.integer)
5332                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5333         if (r_glsl_postprocess_uservec3_enable.integer)
5334                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5335         if (r_glsl_postprocess_uservec4_enable.integer)
5336                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5337
5338         // render to the screen fbo
5339         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5340         GL_Color(1, 1, 1, 1);
5341         GL_BlendFunc(GL_ONE, GL_ZERO);
5342
5343         viewtexture = r_fb.rt_screen->colortexture[0];
5344         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5345
5346         if (r_rendertarget_debug.integer >= 0)
5347         {
5348                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5349                 if (rt && rt->colortexture[0])
5350                 {
5351                         viewtexture = rt->colortexture[0];
5352                         bloomtexture = NULL;
5353                 }
5354         }
5355
5356         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5357         switch(vid.renderpath)
5358         {
5359         case RENDERPATH_GL32:
5360         case RENDERPATH_GLES2:
5361                 permutation =
5362                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5363                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5364                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5365                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5366                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5367                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5368                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5369                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5370                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5371                 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]);
5372                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5373                 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]);
5374                 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]);
5375                 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]);
5376                 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]);
5377                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5378                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5379                 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);
5380                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5381                 break;
5382         }
5383         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5384         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5385 }
5386
5387 matrix4x4_t r_waterscrollmatrix;
5388
5389 void R_UpdateFog(void)
5390 {
5391         // Nehahra fog
5392         if (gamemode == GAME_NEHAHRA)
5393         {
5394                 if (gl_fogenable.integer)
5395                 {
5396                         r_refdef.oldgl_fogenable = true;
5397                         r_refdef.fog_density = gl_fogdensity.value;
5398                         r_refdef.fog_red = gl_fogred.value;
5399                         r_refdef.fog_green = gl_foggreen.value;
5400                         r_refdef.fog_blue = gl_fogblue.value;
5401                         r_refdef.fog_alpha = 1;
5402                         r_refdef.fog_start = 0;
5403                         r_refdef.fog_end = gl_skyclip.value;
5404                         r_refdef.fog_height = 1<<30;
5405                         r_refdef.fog_fadedepth = 128;
5406                 }
5407                 else if (r_refdef.oldgl_fogenable)
5408                 {
5409                         r_refdef.oldgl_fogenable = false;
5410                         r_refdef.fog_density = 0;
5411                         r_refdef.fog_red = 0;
5412                         r_refdef.fog_green = 0;
5413                         r_refdef.fog_blue = 0;
5414                         r_refdef.fog_alpha = 0;
5415                         r_refdef.fog_start = 0;
5416                         r_refdef.fog_end = 0;
5417                         r_refdef.fog_height = 1<<30;
5418                         r_refdef.fog_fadedepth = 128;
5419                 }
5420         }
5421
5422         // fog parms
5423         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5424         r_refdef.fog_start = max(0, r_refdef.fog_start);
5425         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5426
5427         if (r_refdef.fog_density && r_drawfog.integer)
5428         {
5429                 r_refdef.fogenabled = true;
5430                 // this is the point where the fog reaches 0.9986 alpha, which we
5431                 // consider a good enough cutoff point for the texture
5432                 // (0.9986 * 256 == 255.6)
5433                 if (r_fog_exp2.integer)
5434                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5435                 else
5436                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5437                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5438                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5439                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5440                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5441                         R_BuildFogHeightTexture();
5442                 // fog color was already set
5443                 // update the fog texture
5444                 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)
5445                         R_BuildFogTexture();
5446                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5447                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5448         }
5449         else
5450                 r_refdef.fogenabled = false;
5451
5452         // fog color
5453         if (r_refdef.fog_density)
5454         {
5455                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5456                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5457                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5458
5459                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5460                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5461                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5462                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5463
5464                 {
5465                         vec3_t fogvec;
5466                         VectorCopy(r_refdef.fogcolor, fogvec);
5467                         //   color.rgb *= ContrastBoost * SceneBrightness;
5468                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5469                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5470                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5471                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5472                 }
5473         }
5474 }
5475
5476 void R_UpdateVariables(void)
5477 {
5478         R_Textures_Frame();
5479
5480         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5481
5482         r_refdef.farclip = r_farclip_base.value;
5483         if (r_refdef.scene.worldmodel)
5484                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5485         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5486
5487         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5488                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5489         r_refdef.polygonfactor = 0;
5490         r_refdef.polygonoffset = 0;
5491
5492         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5493         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5494         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5495         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5496         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5497         if (r_refdef.scene.worldmodel)
5498         {
5499                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5500         }
5501         if (r_showsurfaces.integer)
5502         {
5503                 r_refdef.scene.rtworld = false;
5504                 r_refdef.scene.rtworldshadows = false;
5505                 r_refdef.scene.rtdlight = false;
5506                 r_refdef.scene.rtdlightshadows = false;
5507                 r_refdef.scene.lightmapintensity = 0;
5508         }
5509
5510         r_gpuskeletal = false;
5511         switch(vid.renderpath)
5512         {
5513         case RENDERPATH_GL32:
5514                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5515         case RENDERPATH_GLES2:
5516                 if(!vid_gammatables_trivial)
5517                 {
5518                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5519                         {
5520                                 // build GLSL gamma texture
5521 #define RAMPWIDTH 256
5522                                 unsigned short ramp[RAMPWIDTH * 3];
5523                                 unsigned char rampbgr[RAMPWIDTH][4];
5524                                 int i;
5525
5526                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5527
5528                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5529                                 for(i = 0; i < RAMPWIDTH; ++i)
5530                                 {
5531                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5532                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5533                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5534                                         rampbgr[i][3] = 0;
5535                                 }
5536                                 if (r_texture_gammaramps)
5537                                 {
5538                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5539                                 }
5540                                 else
5541                                 {
5542                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5543                                 }
5544                         }
5545                 }
5546                 else
5547                 {
5548                         // remove GLSL gamma texture
5549                 }
5550                 break;
5551         }
5552 }
5553
5554 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5555 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5556 /*
5557 ================
5558 R_SelectScene
5559 ================
5560 */
5561 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5562         if( scenetype != r_currentscenetype ) {
5563                 // store the old scenetype
5564                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5565                 r_currentscenetype = scenetype;
5566                 // move in the new scene
5567                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5568         }
5569 }
5570
5571 /*
5572 ================
5573 R_GetScenePointer
5574 ================
5575 */
5576 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5577 {
5578         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5579         if( scenetype == r_currentscenetype ) {
5580                 return &r_refdef.scene;
5581         } else {
5582                 return &r_scenes_store[ scenetype ];
5583         }
5584 }
5585
5586 static int R_SortEntities_Compare(const void *ap, const void *bp)
5587 {
5588         const entity_render_t *a = *(const entity_render_t **)ap;
5589         const entity_render_t *b = *(const entity_render_t **)bp;
5590
5591         // 1. compare model
5592         if(a->model < b->model)
5593                 return -1;
5594         if(a->model > b->model)
5595                 return +1;
5596
5597         // 2. compare skin
5598         // TODO possibly calculate the REAL skinnum here first using
5599         // skinscenes?
5600         if(a->skinnum < b->skinnum)
5601                 return -1;
5602         if(a->skinnum > b->skinnum)
5603                 return +1;
5604
5605         // everything we compared is equal
5606         return 0;
5607 }
5608 static void R_SortEntities(void)
5609 {
5610         // below or equal 2 ents, sorting never gains anything
5611         if(r_refdef.scene.numentities <= 2)
5612                 return;
5613         // sort
5614         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5615 }
5616
5617 /*
5618 ================
5619 R_RenderView
5620 ================
5621 */
5622 extern cvar_t r_shadow_bouncegrid;
5623 extern cvar_t v_isometric;
5624 extern void V_MakeViewIsometric(void);
5625 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5626 {
5627         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5628         int viewfbo = 0;
5629         rtexture_t *viewdepthtexture = NULL;
5630         rtexture_t *viewcolortexture = NULL;
5631         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5632
5633         // finish any 2D rendering that was queued
5634         DrawQ_Finish();
5635
5636         if (r_timereport_active)
5637                 R_TimeReport("start");
5638         r_textureframe++; // used only by R_GetCurrentTexture
5639         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5640
5641         if(R_CompileShader_CheckStaticParms())
5642                 R_GLSL_Restart_f(cmd_local);
5643
5644         if (!r_drawentities.integer)
5645                 r_refdef.scene.numentities = 0;
5646         else if (r_sortentities.integer)
5647                 R_SortEntities();
5648
5649         R_AnimCache_ClearCache();
5650
5651         /* adjust for stereo display */
5652         if(R_Stereo_Active())
5653         {
5654                 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);
5655                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5656         }
5657
5658         if (r_refdef.view.isoverlay)
5659         {
5660                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5661                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5662                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5663                 R_TimeReport("depthclear");
5664
5665                 r_refdef.view.showdebug = false;
5666
5667                 r_fb.water.enabled = false;
5668                 r_fb.water.numwaterplanes = 0;
5669
5670                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5671
5672                 r_refdef.view.matrix = originalmatrix;
5673
5674                 CHECKGLERROR
5675                 return;
5676         }
5677
5678         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5679         {
5680                 r_refdef.view.matrix = originalmatrix;
5681                 return;
5682         }
5683
5684         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5685         if (v_isometric.integer && r_refdef.view.ismain)
5686                 V_MakeViewIsometric();
5687
5688         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5689
5690         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5691                 // in sRGB fallback, behave similar to true sRGB: convert this
5692                 // value from linear to sRGB
5693                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5694
5695         R_RenderView_UpdateViewVectors();
5696
5697         R_Shadow_UpdateWorldLightSelection();
5698
5699         // this will set up r_fb.rt_screen
5700         R_Bloom_StartFrame();
5701
5702         // apply bloom brightness offset
5703         if(r_fb.rt_bloom)
5704                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5705
5706         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5707         if (r_fb.rt_screen)
5708         {
5709                 viewfbo = r_fb.rt_screen->fbo;
5710                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5711                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5712                 viewx = 0;
5713                 viewy = 0;
5714                 viewwidth = r_fb.rt_screen->texturewidth;
5715                 viewheight = r_fb.rt_screen->textureheight;
5716         }
5717
5718         R_Water_StartFrame(viewwidth, viewheight);
5719
5720         CHECKGLERROR
5721         if (r_timereport_active)
5722                 R_TimeReport("viewsetup");
5723
5724         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5725
5726         // clear the whole fbo every frame - otherwise the driver will consider
5727         // it to be an inter-frame texture and stall in multi-gpu configurations
5728         if (r_fb.rt_screen)
5729                 GL_ScissorTest(false);
5730         R_ClearScreen(r_refdef.fogenabled);
5731         if (r_timereport_active)
5732                 R_TimeReport("viewclear");
5733
5734         r_refdef.view.clear = true;
5735
5736         r_refdef.view.showdebug = true;
5737
5738         R_View_Update();
5739         if (r_timereport_active)
5740                 R_TimeReport("visibility");
5741
5742         R_AnimCache_CacheVisibleEntities();
5743         if (r_timereport_active)
5744                 R_TimeReport("animcache");
5745
5746         R_Shadow_UpdateBounceGridTexture();
5747         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5748
5749         r_fb.water.numwaterplanes = 0;
5750         if (r_fb.water.enabled)
5751                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5752
5753         // for the actual view render we use scissoring a fair amount, so scissor
5754         // test needs to be on
5755         if (r_fb.rt_screen)
5756                 GL_ScissorTest(true);
5757         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5758         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5759         r_fb.water.numwaterplanes = 0;
5760
5761         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5762         GL_ScissorTest(false);
5763
5764         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5765         if (r_timereport_active)
5766                 R_TimeReport("blendview");
5767
5768         r_refdef.view.matrix = originalmatrix;
5769
5770         CHECKGLERROR
5771
5772         // go back to 2d rendering
5773         DrawQ_Start();
5774 }
5775
5776 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5777 {
5778         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5779         {
5780                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5781                 if (r_timereport_active)
5782                         R_TimeReport("waterworld");
5783         }
5784
5785         // don't let sound skip if going slow
5786         if (r_refdef.scene.extraupdate)
5787                 S_ExtraUpdate ();
5788
5789         R_DrawModelsAddWaterPlanes();
5790         if (r_timereport_active)
5791                 R_TimeReport("watermodels");
5792
5793         if (r_fb.water.numwaterplanes)
5794         {
5795                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5796                 if (r_timereport_active)
5797                         R_TimeReport("waterscenes");
5798         }
5799 }
5800
5801 extern cvar_t cl_locs_show;
5802 static void R_DrawLocs(void);
5803 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5804 static void R_DrawModelDecals(void);
5805 extern qbool r_shadow_usingdeferredprepass;
5806 extern int r_shadow_shadowmapatlas_modelshadows_size;
5807 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5808 {
5809         qbool shadowmapping = false;
5810
5811         if (r_timereport_active)
5812                 R_TimeReport("beginscene");
5813
5814         r_refdef.stats[r_stat_renders]++;
5815
5816         R_UpdateFog();
5817
5818         // don't let sound skip if going slow
5819         if (r_refdef.scene.extraupdate)
5820                 S_ExtraUpdate ();
5821
5822         R_MeshQueue_BeginScene();
5823
5824         R_SkyStartFrame();
5825
5826         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);
5827
5828         if (r_timereport_active)
5829                 R_TimeReport("skystartframe");
5830
5831         if (cl.csqc_vidvars.drawworld)
5832         {
5833                 // don't let sound skip if going slow
5834                 if (r_refdef.scene.extraupdate)
5835                         S_ExtraUpdate ();
5836
5837                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5838                 {
5839                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5840                         if (r_timereport_active)
5841                                 R_TimeReport("worldsky");
5842                 }
5843
5844                 if (R_DrawBrushModelsSky() && r_timereport_active)
5845                         R_TimeReport("bmodelsky");
5846
5847                 if (skyrendermasked && skyrenderlater)
5848                 {
5849                         // we have to force off the water clipping plane while rendering sky
5850                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5851                         R_Sky();
5852                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5853                         if (r_timereport_active)
5854                                 R_TimeReport("sky");
5855                 }
5856         }
5857
5858         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5859         r_shadow_viewfbo = viewfbo;
5860         r_shadow_viewdepthtexture = viewdepthtexture;
5861         r_shadow_viewcolortexture = viewcolortexture;
5862         r_shadow_viewx = viewx;
5863         r_shadow_viewy = viewy;
5864         r_shadow_viewwidth = viewwidth;
5865         r_shadow_viewheight = viewheight;
5866
5867         R_Shadow_PrepareModelShadows();
5868         R_Shadow_PrepareLights();
5869         if (r_timereport_active)
5870                 R_TimeReport("preparelights");
5871
5872         // render all the shadowmaps that will be used for this view
5873         shadowmapping = R_Shadow_ShadowMappingEnabled();
5874         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5875         {
5876                 R_Shadow_DrawShadowMaps();
5877                 if (r_timereport_active)
5878                         R_TimeReport("shadowmaps");
5879         }
5880
5881         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5882         if (r_shadow_usingdeferredprepass)
5883                 R_Shadow_DrawPrepass();
5884
5885         // now we begin the forward pass of the view render
5886         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5887         {
5888                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5889                 if (r_timereport_active)
5890                         R_TimeReport("worlddepth");
5891         }
5892         if (r_depthfirst.integer >= 2)
5893         {
5894                 R_DrawModelsDepth();
5895                 if (r_timereport_active)
5896                         R_TimeReport("modeldepth");
5897         }
5898
5899         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5900         {
5901                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5902                 if (r_timereport_active)
5903                         R_TimeReport("world");
5904         }
5905
5906         // don't let sound skip if going slow
5907         if (r_refdef.scene.extraupdate)
5908                 S_ExtraUpdate ();
5909
5910         R_DrawModels();
5911         if (r_timereport_active)
5912                 R_TimeReport("models");
5913
5914         // don't let sound skip if going slow
5915         if (r_refdef.scene.extraupdate)
5916                 S_ExtraUpdate ();
5917
5918         if (!r_shadow_usingdeferredprepass)
5919         {
5920                 R_Shadow_DrawLights();
5921                 if (r_timereport_active)
5922                         R_TimeReport("rtlights");
5923         }
5924
5925         // don't let sound skip if going slow
5926         if (r_refdef.scene.extraupdate)
5927                 S_ExtraUpdate ();
5928
5929         if (cl.csqc_vidvars.drawworld)
5930         {
5931                 R_DrawModelDecals();
5932                 if (r_timereport_active)
5933                         R_TimeReport("modeldecals");
5934
5935                 R_DrawParticles();
5936                 if (r_timereport_active)
5937                         R_TimeReport("particles");
5938
5939                 R_DrawExplosions();
5940                 if (r_timereport_active)
5941                         R_TimeReport("explosions");
5942         }
5943
5944         if (r_refdef.view.showdebug)
5945         {
5946                 if (cl_locs_show.integer)
5947                 {
5948                         R_DrawLocs();
5949                         if (r_timereport_active)
5950                                 R_TimeReport("showlocs");
5951                 }
5952
5953                 if (r_drawportals.integer)
5954                 {
5955                         R_DrawPortals();
5956                         if (r_timereport_active)
5957                                 R_TimeReport("portals");
5958                 }
5959
5960                 if (r_showbboxes_client.value > 0)
5961                 {
5962                         R_DrawEntityBBoxes(CLVM_prog);
5963                         if (r_timereport_active)
5964                                 R_TimeReport("clbboxes");
5965                 }
5966                 if (r_showbboxes.value > 0)
5967                 {
5968                         R_DrawEntityBBoxes(SVVM_prog);
5969                         if (r_timereport_active)
5970                                 R_TimeReport("svbboxes");
5971                 }
5972         }
5973
5974         if (r_transparent.integer)
5975         {
5976                 R_MeshQueue_RenderTransparent();
5977                 if (r_timereport_active)
5978                         R_TimeReport("drawtrans");
5979         }
5980
5981         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))
5982         {
5983                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5984                 if (r_timereport_active)
5985                         R_TimeReport("worlddebug");
5986                 R_DrawModelsDebug();
5987                 if (r_timereport_active)
5988                         R_TimeReport("modeldebug");
5989         }
5990
5991         if (cl.csqc_vidvars.drawworld)
5992         {
5993                 R_Shadow_DrawCoronas();
5994                 if (r_timereport_active)
5995                         R_TimeReport("coronas");
5996         }
5997
5998         // don't let sound skip if going slow
5999         if (r_refdef.scene.extraupdate)
6000                 S_ExtraUpdate ();
6001 }
6002
6003 static const unsigned short bboxelements[36] =
6004 {
6005         5, 1, 3, 5, 3, 7,
6006         6, 2, 0, 6, 0, 4,
6007         7, 3, 2, 7, 2, 6,
6008         4, 0, 1, 4, 1, 5,
6009         4, 5, 7, 4, 7, 6,
6010         1, 0, 2, 1, 2, 3,
6011 };
6012
6013 #define BBOXEDGES 13
6014 static const float bboxedges[BBOXEDGES][6] = 
6015 {
6016         // whole box
6017         { 0, 0, 0, 1, 1, 1 },
6018         // bottom edges
6019         { 0, 0, 0, 0, 1, 0 },
6020         { 0, 0, 0, 1, 0, 0 },
6021         { 0, 1, 0, 1, 1, 0 },
6022         { 1, 0, 0, 1, 1, 0 },
6023         // top edges
6024         { 0, 0, 1, 0, 1, 1 },
6025         { 0, 0, 1, 1, 0, 1 },
6026         { 0, 1, 1, 1, 1, 1 },
6027         { 1, 0, 1, 1, 1, 1 },
6028         // vertical edges
6029         { 0, 0, 0, 0, 0, 1 },
6030         { 1, 0, 0, 1, 0, 1 },
6031         { 0, 1, 0, 0, 1, 1 },
6032         { 1, 1, 0, 1, 1, 1 },
6033 };
6034
6035 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6036 {
6037         int numvertices = BBOXEDGES * 8;
6038         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6039         int numtriangles = BBOXEDGES * 12;
6040         unsigned short elements[BBOXEDGES * 36];
6041         int i, edge;
6042         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6043
6044         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6045
6046         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6047         GL_DepthMask(false);
6048         GL_DepthRange(0, 1);
6049         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6050
6051         for (edge = 0; edge < BBOXEDGES; edge++)
6052         {
6053                 for (i = 0; i < 3; i++)
6054                 {
6055                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6056                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6057                 }
6058                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6059                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6060                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6061                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6062                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6063                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6064                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6065                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6066                 for (i = 0; i < 36; i++)
6067                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6068         }
6069         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6070         if (r_refdef.fogenabled)
6071         {
6072                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6073                 {
6074                         f1 = RSurf_FogVertex(v);
6075                         f2 = 1 - f1;
6076                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6077                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6078                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6079                 }
6080         }
6081         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6082         R_Mesh_ResetTextureState();
6083         R_SetupShader_Generic_NoTexture(false, false);
6084         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6085 }
6086
6087 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6088 {
6089         // hacky overloading of the parameters
6090         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6091         int i;
6092         float color[4];
6093         prvm_edict_t *edict;
6094
6095         GL_CullFace(GL_NONE);
6096         R_SetupShader_Generic_NoTexture(false, false);
6097
6098         for (i = 0;i < numsurfaces;i++)
6099         {
6100                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6101                 switch ((int)PRVM_serveredictfloat(edict, solid))
6102                 {
6103                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6104                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6105                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6106                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6107                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6108                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6109                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6110                 }
6111                 if (prog == CLVM_prog)
6112                         color[3] *= r_showbboxes_client.value;
6113                 else
6114                         color[3] *= r_showbboxes.value;
6115                 color[3] = bound(0, color[3], 1);
6116                 GL_DepthTest(!r_showdisabledepthtest.integer);
6117                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6118         }
6119 }
6120
6121 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6122 {
6123         int i;
6124         prvm_edict_t *edict;
6125         vec3_t center;
6126
6127         if (prog == NULL)
6128                 return;
6129
6130         for (i = 0; i < prog->num_edicts; i++)
6131         {
6132                 edict = PRVM_EDICT_NUM(i);
6133                 if (edict->free)
6134                         continue;
6135                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6136                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6137                         continue;
6138                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6139                         continue;
6140                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6141                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6142         }
6143 }
6144
6145 static const int nomodelelement3i[24] =
6146 {
6147         5, 2, 0,
6148         5, 1, 2,
6149         5, 0, 3,
6150         5, 3, 1,
6151         0, 2, 4,
6152         2, 1, 4,
6153         3, 0, 4,
6154         1, 3, 4
6155 };
6156
6157 static const unsigned short nomodelelement3s[24] =
6158 {
6159         5, 2, 0,
6160         5, 1, 2,
6161         5, 0, 3,
6162         5, 3, 1,
6163         0, 2, 4,
6164         2, 1, 4,
6165         3, 0, 4,
6166         1, 3, 4
6167 };
6168
6169 static const float nomodelvertex3f[6*3] =
6170 {
6171         -16,   0,   0,
6172          16,   0,   0,
6173           0, -16,   0,
6174           0,  16,   0,
6175           0,   0, -16,
6176           0,   0,  16
6177 };
6178
6179 static const float nomodelcolor4f[6*4] =
6180 {
6181         0.0f, 0.0f, 0.5f, 1.0f,
6182         0.0f, 0.0f, 0.5f, 1.0f,
6183         0.0f, 0.5f, 0.0f, 1.0f,
6184         0.0f, 0.5f, 0.0f, 1.0f,
6185         0.5f, 0.0f, 0.0f, 1.0f,
6186         0.5f, 0.0f, 0.0f, 1.0f
6187 };
6188
6189 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6190 {
6191         int i;
6192         float f1, f2, *c;
6193         float color4f[6*4];
6194
6195         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);
6196
6197         // this is only called once per entity so numsurfaces is always 1, and
6198         // surfacelist is always {0}, so this code does not handle batches
6199
6200         if (rsurface.ent_flags & RENDER_ADDITIVE)
6201         {
6202                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6203                 GL_DepthMask(false);
6204         }
6205         else if (ent->alpha < 1)
6206         {
6207                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6208                 GL_DepthMask(false);
6209         }
6210         else
6211         {
6212                 GL_BlendFunc(GL_ONE, GL_ZERO);
6213                 GL_DepthMask(true);
6214         }
6215         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6216         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6217         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6218         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6219         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6220         for (i = 0, c = color4f;i < 6;i++, c += 4)
6221         {
6222                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6223                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6224                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6225                 c[3] *= ent->alpha;
6226         }
6227         if (r_refdef.fogenabled)
6228         {
6229                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6230                 {
6231                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6232                         f2 = 1 - f1;
6233                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6234                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6235                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6236                 }
6237         }
6238 //      R_Mesh_ResetTextureState();
6239         R_SetupShader_Generic_NoTexture(false, false);
6240         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6241         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6242 }
6243
6244 void R_DrawNoModel(entity_render_t *ent)
6245 {
6246         vec3_t org;
6247         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6248         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6249                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6250         else
6251                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6252 }
6253
6254 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6255 {
6256         vec3_t right1, right2, diff, normal;
6257
6258         VectorSubtract (org2, org1, normal);
6259
6260         // calculate 'right' vector for start
6261         VectorSubtract (r_refdef.view.origin, org1, diff);
6262         CrossProduct (normal, diff, right1);
6263         VectorNormalize (right1);
6264
6265         // calculate 'right' vector for end
6266         VectorSubtract (r_refdef.view.origin, org2, diff);
6267         CrossProduct (normal, diff, right2);
6268         VectorNormalize (right2);
6269
6270         vert[ 0] = org1[0] + width * right1[0];
6271         vert[ 1] = org1[1] + width * right1[1];
6272         vert[ 2] = org1[2] + width * right1[2];
6273         vert[ 3] = org1[0] - width * right1[0];
6274         vert[ 4] = org1[1] - width * right1[1];
6275         vert[ 5] = org1[2] - width * right1[2];
6276         vert[ 6] = org2[0] - width * right2[0];
6277         vert[ 7] = org2[1] - width * right2[1];
6278         vert[ 8] = org2[2] - width * right2[2];
6279         vert[ 9] = org2[0] + width * right2[0];
6280         vert[10] = org2[1] + width * right2[1];
6281         vert[11] = org2[2] + width * right2[2];
6282 }
6283
6284 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)
6285 {
6286         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6287         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6288         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6289         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6290         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6291         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6292         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6293         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6294         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6295         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6296         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6297         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6298 }
6299
6300 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6301 {
6302         int i;
6303         float *vertex3f;
6304         float v[3];
6305         VectorSet(v, x, y, z);
6306         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6307                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6308                         break;
6309         if (i == mesh->numvertices)
6310         {
6311                 if (mesh->numvertices < mesh->maxvertices)
6312                 {
6313                         VectorCopy(v, vertex3f);
6314                         mesh->numvertices++;
6315                 }
6316                 return mesh->numvertices;
6317         }
6318         else
6319                 return i;
6320 }
6321
6322 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6323 {
6324         int i;
6325         int *e, element[3];
6326         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6327         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6328         e = mesh->element3i + mesh->numtriangles * 3;
6329         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6330         {
6331                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6332                 if (mesh->numtriangles < mesh->maxtriangles)
6333                 {
6334                         *e++ = element[0];
6335                         *e++ = element[1];
6336                         *e++ = element[2];
6337                         mesh->numtriangles++;
6338                 }
6339                 element[1] = element[2];
6340         }
6341 }
6342
6343 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6344 {
6345         int i;
6346         int *e, element[3];
6347         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6348         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6349         e = mesh->element3i + mesh->numtriangles * 3;
6350         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6351         {
6352                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6353                 if (mesh->numtriangles < mesh->maxtriangles)
6354                 {
6355                         *e++ = element[0];
6356                         *e++ = element[1];
6357                         *e++ = element[2];
6358                         mesh->numtriangles++;
6359                 }
6360                 element[1] = element[2];
6361         }
6362 }
6363
6364 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6365 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6366 {
6367         int planenum, planenum2;
6368         int w;
6369         int tempnumpoints;
6370         mplane_t *plane, *plane2;
6371         double maxdist;
6372         double temppoints[2][256*3];
6373         // figure out how large a bounding box we need to properly compute this brush
6374         maxdist = 0;
6375         for (w = 0;w < numplanes;w++)
6376                 maxdist = max(maxdist, fabs(planes[w].dist));
6377         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6378         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6379         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6380         {
6381                 w = 0;
6382                 tempnumpoints = 4;
6383                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6384                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6385                 {
6386                         if (planenum2 == planenum)
6387                                 continue;
6388                         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);
6389                         w = !w;
6390                 }
6391                 if (tempnumpoints < 3)
6392                         continue;
6393                 // generate elements forming a triangle fan for this polygon
6394                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6395         }
6396 }
6397
6398 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6399 {
6400         if(parms[0] == 0 && parms[1] == 0)
6401                 return false;
6402         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6403                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6404                         return false;
6405         return true;
6406 }
6407
6408 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6409 {
6410         double index, f;
6411         index = parms[2] + rsurface.shadertime * parms[3];
6412         index -= floor(index);
6413         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6414         {
6415         default:
6416         case Q3WAVEFUNC_NONE:
6417         case Q3WAVEFUNC_NOISE:
6418         case Q3WAVEFUNC_COUNT:
6419                 f = 0;
6420                 break;
6421         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6422         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6423         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6424         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6425         case Q3WAVEFUNC_TRIANGLE:
6426                 index *= 4;
6427                 f = index - floor(index);
6428                 if (index < 1)
6429                 {
6430                         // f = f;
6431                 }
6432                 else if (index < 2)
6433                         f = 1 - f;
6434                 else if (index < 3)
6435                         f = -f;
6436                 else
6437                         f = -(1 - f);
6438                 break;
6439         }
6440         f = parms[0] + parms[1] * f;
6441         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6442                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6443         return (float) f;
6444 }
6445
6446 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6447 {
6448         int w, h, idx;
6449         float shadertime;
6450         float f;
6451         float offsetd[2];
6452         float tcmat[12];
6453         matrix4x4_t matrix, temp;
6454         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6455         // it's better to have one huge fixup every 9 hours than gradual
6456         // degradation over time which looks consistently bad after many hours.
6457         //
6458         // tcmod scroll in particular suffers from this degradation which can't be
6459         // effectively worked around even with floor() tricks because we don't
6460         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6461         // a workaround involving floor() would be incorrect anyway...
6462         shadertime = rsurface.shadertime;
6463         if (shadertime >= 32768.0f)
6464                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6465         switch(tcmod->tcmod)
6466         {
6467                 case Q3TCMOD_COUNT:
6468                 case Q3TCMOD_NONE:
6469                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6470                                 matrix = r_waterscrollmatrix;
6471                         else
6472                                 matrix = identitymatrix;
6473                         break;
6474                 case Q3TCMOD_ENTITYTRANSLATE:
6475                         // this is used in Q3 to allow the gamecode to control texcoord
6476                         // scrolling on the entity, which is not supported in darkplaces yet.
6477                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6478                         break;
6479                 case Q3TCMOD_ROTATE:
6480                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6481                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6482                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6483                         break;
6484                 case Q3TCMOD_SCALE:
6485                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6486                         break;
6487                 case Q3TCMOD_SCROLL:
6488                         // this particular tcmod is a "bug for bug" compatible one with regards to
6489                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6490                         // specifically did the wrapping and so we must mimic that...
6491                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6492                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6493                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6494                         break;
6495                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6496                         w = (int) tcmod->parms[0];
6497                         h = (int) tcmod->parms[1];
6498                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6499                         f = f - floor(f);
6500                         idx = (int) floor(f * w * h);
6501                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6502                         break;
6503                 case Q3TCMOD_STRETCH:
6504                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6505                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6506                         break;
6507                 case Q3TCMOD_TRANSFORM:
6508                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6509                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6510                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6511                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6512                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6513                         break;
6514                 case Q3TCMOD_TURBULENT:
6515                         // this is handled in the RSurf_PrepareVertices function
6516                         matrix = identitymatrix;
6517                         break;
6518         }
6519         temp = *texmatrix;
6520         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6521 }
6522
6523 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6524 {
6525         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6526         char name[MAX_QPATH];
6527         skinframe_t *skinframe;
6528         unsigned char pixels[296*194];
6529         strlcpy(cache->name, skinname, sizeof(cache->name));
6530         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6531         if (developer_loading.integer)
6532                 Con_Printf("loading %s\n", name);
6533         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6534         if (!skinframe || !skinframe->base)
6535         {
6536                 unsigned char *f;
6537                 fs_offset_t filesize;
6538                 skinframe = NULL;
6539                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6540                 if (f)
6541                 {
6542                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6543                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6544                         Mem_Free(f);
6545                 }
6546         }
6547         cache->skinframe = skinframe;
6548 }
6549
6550 texture_t *R_GetCurrentTexture(texture_t *t)
6551 {
6552         int i, q;
6553         const entity_render_t *ent = rsurface.entity;
6554         model_t *model = ent->model; // when calling this, ent must not be NULL
6555         q3shaderinfo_layer_tcmod_t *tcmod;
6556         float specularscale = 0.0f;
6557
6558         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6559                 return t->currentframe;
6560         t->update_lastrenderframe = r_textureframe;
6561         t->update_lastrenderentity = (void *)ent;
6562
6563         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6564                 t->camera_entity = ent->entitynumber;
6565         else
6566                 t->camera_entity = 0;
6567
6568         // switch to an alternate material if this is a q1bsp animated material
6569         {
6570                 texture_t *texture = t;
6571                 int s = rsurface.ent_skinnum;
6572                 if ((unsigned int)s >= (unsigned int)model->numskins)
6573                         s = 0;
6574                 if (model->skinscenes)
6575                 {
6576                         if (model->skinscenes[s].framecount > 1)
6577                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6578                         else
6579                                 s = model->skinscenes[s].firstframe;
6580                 }
6581                 if (s > 0)
6582                         t = t + s * model->num_surfaces;
6583                 if (t->animated)
6584                 {
6585                         // use an alternate animation if the entity's frame is not 0,
6586                         // and only if the texture has an alternate animation
6587                         if (t->animated == 2) // q2bsp
6588                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6589                         else if (rsurface.ent_alttextures && t->anim_total[1])
6590                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6591                         else
6592                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6593                 }
6594                 texture->currentframe = t;
6595         }
6596
6597         // update currentskinframe to be a qw skin or animation frame
6598         if (rsurface.ent_qwskin >= 0)
6599         {
6600                 i = rsurface.ent_qwskin;
6601                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6602                 {
6603                         r_qwskincache_size = cl.maxclients;
6604                         if (r_qwskincache)
6605                                 Mem_Free(r_qwskincache);
6606                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6607                 }
6608                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6609                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6610                 t->currentskinframe = r_qwskincache[i].skinframe;
6611                 if (t->materialshaderpass && t->currentskinframe == NULL)
6612                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6613         }
6614         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6615                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6616         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6617                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6618
6619         t->currentmaterialflags = t->basematerialflags;
6620         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6621         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6622                 t->currentalpha *= r_wateralpha.value;
6623         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6624                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6625         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6626                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6627
6628         // decide on which type of lighting to use for this surface
6629         if (rsurface.entity->render_modellight_forced)
6630                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6631         if (rsurface.entity->render_rtlight_disabled)
6632                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6633         if (rsurface.entity->render_lightgrid)
6634                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6635         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6636         {
6637                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6638                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6639                 for (q = 0; q < 3; q++)
6640                 {
6641                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6642                         t->render_modellight_lightdir_world[q] = q == 2;
6643                         t->render_modellight_lightdir_local[q] = q == 2;
6644                         t->render_modellight_ambient[q] = 1;
6645                         t->render_modellight_diffuse[q] = 0;
6646                         t->render_modellight_specular[q] = 0;
6647                         t->render_lightmap_ambient[q] = 0;
6648                         t->render_lightmap_diffuse[q] = 0;
6649                         t->render_lightmap_specular[q] = 0;
6650                         t->render_rtlight_diffuse[q] = 0;
6651                         t->render_rtlight_specular[q] = 0;
6652                 }
6653         }
6654         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6655         {
6656                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6657                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6658                 for (q = 0; q < 3; q++)
6659                 {
6660                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6661                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6662                         t->render_modellight_lightdir_world[q] = q == 2;
6663                         t->render_modellight_lightdir_local[q] = q == 2;
6664                         t->render_modellight_diffuse[q] = 0;
6665                         t->render_modellight_specular[q] = 0;
6666                         t->render_lightmap_ambient[q] = 0;
6667                         t->render_lightmap_diffuse[q] = 0;
6668                         t->render_lightmap_specular[q] = 0;
6669                         t->render_rtlight_diffuse[q] = 0;
6670                         t->render_rtlight_specular[q] = 0;
6671                 }
6672         }
6673         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6674         {
6675                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6676                 for (q = 0; q < 3; q++)
6677                 {
6678                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6679                         t->render_modellight_lightdir_world[q] = q == 2;
6680                         t->render_modellight_lightdir_local[q] = q == 2;
6681                         t->render_modellight_ambient[q] = 0;
6682                         t->render_modellight_diffuse[q] = 0;
6683                         t->render_modellight_specular[q] = 0;
6684                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6685                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6686                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6687                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6688                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6689                 }
6690         }
6691         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6692         {
6693                 // ambient + single direction light (modellight)
6694                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6695                 for (q = 0; q < 3; q++)
6696                 {
6697                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6698                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6699                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6700                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6701                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6702                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6703                         t->render_lightmap_ambient[q] = 0;
6704                         t->render_lightmap_diffuse[q] = 0;
6705                         t->render_lightmap_specular[q] = 0;
6706                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6707                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6708                 }
6709         }
6710         else
6711         {
6712                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6713                 for (q = 0; q < 3; q++)
6714                 {
6715                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6716                         t->render_modellight_lightdir_world[q] = q == 2;
6717                         t->render_modellight_lightdir_local[q] = q == 2;
6718                         t->render_modellight_ambient[q] = 0;
6719                         t->render_modellight_diffuse[q] = 0;
6720                         t->render_modellight_specular[q] = 0;
6721                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6722                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6723                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6724                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6725                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6726                 }
6727         }
6728
6729         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6730         {
6731                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6732                 // attribute, we punt it to the lightmap path and hope for the best,
6733                 // but lighting doesn't work.
6734                 //
6735                 // FIXME: this is fine for effects but CSQC polygons should be subject
6736                 // to lighting.
6737                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6738                 for (q = 0; q < 3; q++)
6739                 {
6740                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6741                         t->render_modellight_lightdir_world[q] = q == 2;
6742                         t->render_modellight_lightdir_local[q] = q == 2;
6743                         t->render_modellight_ambient[q] = 0;
6744                         t->render_modellight_diffuse[q] = 0;
6745                         t->render_modellight_specular[q] = 0;
6746                         t->render_lightmap_ambient[q] = 0;
6747                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6748                         t->render_lightmap_specular[q] = 0;
6749                         t->render_rtlight_diffuse[q] = 0;
6750                         t->render_rtlight_specular[q] = 0;
6751                 }
6752         }
6753
6754         for (q = 0; q < 3; q++)
6755         {
6756                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6757                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6758         }
6759
6760         if (rsurface.ent_flags & RENDER_ADDITIVE)
6761                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6762         else if (t->currentalpha < 1)
6763                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6764         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6765         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6766                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6767         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6768                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6769         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6770                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6771         if (t->backgroundshaderpass)
6772                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6773         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6774         {
6775                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6776                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6777         }
6778         else
6779                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6780         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6781         {
6782                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6783                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6784         }
6785         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6786                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6787
6788         // there is no tcmod
6789         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6790         {
6791                 t->currenttexmatrix = r_waterscrollmatrix;
6792                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6793         }
6794         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6795         {
6796                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6797                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6798         }
6799
6800         if (t->materialshaderpass)
6801                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6802                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6803
6804         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6805         if (t->currentskinframe->qpixels)
6806                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6807         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6808         if (!t->basetexture)
6809                 t->basetexture = r_texture_notexture;
6810         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6811         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6812         t->nmaptexture = t->currentskinframe->nmap;
6813         if (!t->nmaptexture)
6814                 t->nmaptexture = r_texture_blanknormalmap;
6815         t->glosstexture = r_texture_black;
6816         t->glowtexture = t->currentskinframe->glow;
6817         t->fogtexture = t->currentskinframe->fog;
6818         t->reflectmasktexture = t->currentskinframe->reflect;
6819         if (t->backgroundshaderpass)
6820         {
6821                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6822                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6823                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6824                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6825                 t->backgroundglosstexture = r_texture_black;
6826                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6827                 if (!t->backgroundnmaptexture)
6828                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6829                 // make sure that if glow is going to be used, both textures are not NULL
6830                 if (!t->backgroundglowtexture && t->glowtexture)
6831                         t->backgroundglowtexture = r_texture_black;
6832                 if (!t->glowtexture && t->backgroundglowtexture)
6833                         t->glowtexture = r_texture_black;
6834         }
6835         else
6836         {
6837                 t->backgroundbasetexture = r_texture_white;
6838                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6839                 t->backgroundglosstexture = r_texture_black;
6840                 t->backgroundglowtexture = NULL;
6841         }
6842         t->specularpower = r_shadow_glossexponent.value;
6843         // TODO: store reference values for these in the texture?
6844         if (r_shadow_gloss.integer > 0)
6845         {
6846                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6847                 {
6848                         if (r_shadow_glossintensity.value > 0)
6849                         {
6850                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6851                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6852                                 specularscale = r_shadow_glossintensity.value;
6853                         }
6854                 }
6855                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6856                 {
6857                         t->glosstexture = r_texture_white;
6858                         t->backgroundglosstexture = r_texture_white;
6859                         specularscale = r_shadow_gloss2intensity.value;
6860                         t->specularpower = r_shadow_gloss2exponent.value;
6861                 }
6862         }
6863         specularscale *= t->specularscalemod;
6864         t->specularpower *= t->specularpowermod;
6865
6866         // lightmaps mode looks bad with dlights using actual texturing, so turn
6867         // off the colormap and glossmap, but leave the normalmap on as it still
6868         // accurately represents the shading involved
6869         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6870         {
6871                 t->basetexture = r_texture_grey128;
6872                 t->pantstexture = r_texture_black;
6873                 t->shirttexture = r_texture_black;
6874                 if (gl_lightmaps.integer < 2)
6875                         t->nmaptexture = r_texture_blanknormalmap;
6876                 t->glosstexture = r_texture_black;
6877                 t->glowtexture = NULL;
6878                 t->fogtexture = NULL;
6879                 t->reflectmasktexture = NULL;
6880                 t->backgroundbasetexture = NULL;
6881                 if (gl_lightmaps.integer < 2)
6882                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6883                 t->backgroundglosstexture = r_texture_black;
6884                 t->backgroundglowtexture = NULL;
6885                 specularscale = 0;
6886                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6887         }
6888
6889         if (specularscale != 1.0f)
6890         {
6891                 for (q = 0; q < 3; q++)
6892                 {
6893                         t->render_modellight_specular[q] *= specularscale;
6894                         t->render_lightmap_specular[q] *= specularscale;
6895                         t->render_rtlight_specular[q] *= specularscale;
6896                 }
6897         }
6898
6899         t->currentblendfunc[0] = GL_ONE;
6900         t->currentblendfunc[1] = GL_ZERO;
6901         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6902         {
6903                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6904                 t->currentblendfunc[1] = GL_ONE;
6905         }
6906         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6907         {
6908                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6909                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6910         }
6911         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6912         {
6913                 t->currentblendfunc[0] = t->customblendfunc[0];
6914                 t->currentblendfunc[1] = t->customblendfunc[1];
6915         }
6916
6917         return t;
6918 }
6919
6920 rsurfacestate_t rsurface;
6921
6922 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6923 {
6924         model_t *model = ent->model;
6925         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6926         //      return;
6927         rsurface.entity = (entity_render_t *)ent;
6928         rsurface.skeleton = ent->skeleton;
6929         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6930         rsurface.ent_skinnum = ent->skinnum;
6931         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;
6932         rsurface.ent_flags = ent->flags;
6933         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6934                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6935         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6936         rsurface.matrix = ent->matrix;
6937         rsurface.inversematrix = ent->inversematrix;
6938         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6939         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6940         R_EntityMatrix(&rsurface.matrix);
6941         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6942         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6943         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6944         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6945         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6946         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6947         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6948         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6949         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6950         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6951         if (ent->model->brush.submodel && !prepass)
6952         {
6953                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6954                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6955         }
6956         // if the animcache code decided it should use the shader path, skip the deform step
6957         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6958         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6959         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6960         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6961         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6962         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6963         {
6964                 if (ent->animcache_vertex3f)
6965                 {
6966                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6967                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6968                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6969                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6970                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6971                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6972                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6973                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6974                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6975                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6976                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6977                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6978                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6979                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6980                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6981                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6982                 }
6983                 else if (wanttangents)
6984                 {
6985                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6986                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6987                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6988                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6989                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6990                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6991                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6992                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6993                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6994                         rsurface.modelvertex3f_vertexbuffer = NULL;
6995                         rsurface.modelvertex3f_bufferoffset = 0;
6996                         rsurface.modelvertex3f_vertexbuffer = 0;
6997                         rsurface.modelvertex3f_bufferoffset = 0;
6998                         rsurface.modelsvector3f_vertexbuffer = 0;
6999                         rsurface.modelsvector3f_bufferoffset = 0;
7000                         rsurface.modeltvector3f_vertexbuffer = 0;
7001                         rsurface.modeltvector3f_bufferoffset = 0;
7002                         rsurface.modelnormal3f_vertexbuffer = 0;
7003                         rsurface.modelnormal3f_bufferoffset = 0;
7004                 }
7005                 else if (wantnormals)
7006                 {
7007                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7008                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7009                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7010                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7011                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7012                         rsurface.modelsvector3f = NULL;
7013                         rsurface.modeltvector3f = NULL;
7014                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7015                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7016                         rsurface.modelvertex3f_vertexbuffer = NULL;
7017                         rsurface.modelvertex3f_bufferoffset = 0;
7018                         rsurface.modelvertex3f_vertexbuffer = 0;
7019                         rsurface.modelvertex3f_bufferoffset = 0;
7020                         rsurface.modelsvector3f_vertexbuffer = 0;
7021                         rsurface.modelsvector3f_bufferoffset = 0;
7022                         rsurface.modeltvector3f_vertexbuffer = 0;
7023                         rsurface.modeltvector3f_bufferoffset = 0;
7024                         rsurface.modelnormal3f_vertexbuffer = 0;
7025                         rsurface.modelnormal3f_bufferoffset = 0;
7026                 }
7027                 else
7028                 {
7029                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7030                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7031                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7032                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7033                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7034                         rsurface.modelsvector3f = NULL;
7035                         rsurface.modeltvector3f = NULL;
7036                         rsurface.modelnormal3f = NULL;
7037                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7038                         rsurface.modelvertex3f_vertexbuffer = NULL;
7039                         rsurface.modelvertex3f_bufferoffset = 0;
7040                         rsurface.modelvertex3f_vertexbuffer = 0;
7041                         rsurface.modelvertex3f_bufferoffset = 0;
7042                         rsurface.modelsvector3f_vertexbuffer = 0;
7043                         rsurface.modelsvector3f_bufferoffset = 0;
7044                         rsurface.modeltvector3f_vertexbuffer = 0;
7045                         rsurface.modeltvector3f_bufferoffset = 0;
7046                         rsurface.modelnormal3f_vertexbuffer = 0;
7047                         rsurface.modelnormal3f_bufferoffset = 0;
7048                 }
7049                 rsurface.modelgeneratedvertex = true;
7050         }
7051         else
7052         {
7053                 if (rsurface.entityskeletaltransform3x4)
7054                 {
7055                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7056                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7057                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7058                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7059                 }
7060                 else
7061                 {
7062                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7063                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7064                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7065                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7066                 }
7067                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7068                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7069                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7070                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7071                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7072                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7073                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7074                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7075                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7076                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7077                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7078                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7079                 rsurface.modelgeneratedvertex = false;
7080         }
7081         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7082         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7083         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7084         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7085         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7086         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7087         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7088         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7089         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7090         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7091         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7092         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7093         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7094         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7095         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7096         rsurface.modelelement3i = model->surfmesh.data_element3i;
7097         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7098         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7099         rsurface.modelelement3s = model->surfmesh.data_element3s;
7100         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7101         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7102         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7103         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7104         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7105         rsurface.modelsurfaces = model->data_surfaces;
7106         rsurface.batchgeneratedvertex = false;
7107         rsurface.batchfirstvertex = 0;
7108         rsurface.batchnumvertices = 0;
7109         rsurface.batchfirsttriangle = 0;
7110         rsurface.batchnumtriangles = 0;
7111         rsurface.batchvertex3f  = NULL;
7112         rsurface.batchvertex3f_vertexbuffer = NULL;
7113         rsurface.batchvertex3f_bufferoffset = 0;
7114         rsurface.batchsvector3f = NULL;
7115         rsurface.batchsvector3f_vertexbuffer = NULL;
7116         rsurface.batchsvector3f_bufferoffset = 0;
7117         rsurface.batchtvector3f = NULL;
7118         rsurface.batchtvector3f_vertexbuffer = NULL;
7119         rsurface.batchtvector3f_bufferoffset = 0;
7120         rsurface.batchnormal3f  = NULL;
7121         rsurface.batchnormal3f_vertexbuffer = NULL;
7122         rsurface.batchnormal3f_bufferoffset = 0;
7123         rsurface.batchlightmapcolor4f = NULL;
7124         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7125         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7126         rsurface.batchtexcoordtexture2f = NULL;
7127         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7128         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7129         rsurface.batchtexcoordlightmap2f = NULL;
7130         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7131         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7132         rsurface.batchskeletalindex4ub = NULL;
7133         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7134         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7135         rsurface.batchskeletalweight4ub = NULL;
7136         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7137         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7138         rsurface.batchelement3i = NULL;
7139         rsurface.batchelement3i_indexbuffer = NULL;
7140         rsurface.batchelement3i_bufferoffset = 0;
7141         rsurface.batchelement3s = NULL;
7142         rsurface.batchelement3s_indexbuffer = NULL;
7143         rsurface.batchelement3s_bufferoffset = 0;
7144         rsurface.forcecurrenttextureupdate = false;
7145 }
7146
7147 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)
7148 {
7149         rsurface.entity = r_refdef.scene.worldentity;
7150         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7151                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7152                 // A better approach could be making this copy only once per frame.
7153                 static entity_render_t custom_entity;
7154                 int q;
7155                 custom_entity = *rsurface.entity;
7156                 for (q = 0; q < 3; ++q) {
7157                         float colormod = q == 0 ? r : q == 1 ? g : b;
7158                         custom_entity.render_fullbright[q] *= colormod;
7159                         custom_entity.render_modellight_ambient[q] *= colormod;
7160                         custom_entity.render_modellight_diffuse[q] *= colormod;
7161                         custom_entity.render_lightmap_ambient[q] *= colormod;
7162                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7163                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7164                 }
7165                 custom_entity.alpha *= a;
7166                 rsurface.entity = &custom_entity;
7167         }
7168         rsurface.skeleton = NULL;
7169         rsurface.ent_skinnum = 0;
7170         rsurface.ent_qwskin = -1;
7171         rsurface.ent_flags = entflags;
7172         rsurface.shadertime = r_refdef.scene.time - shadertime;
7173         rsurface.modelnumvertices = numvertices;
7174         rsurface.modelnumtriangles = numtriangles;
7175         rsurface.matrix = *matrix;
7176         rsurface.inversematrix = *inversematrix;
7177         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7178         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7179         R_EntityMatrix(&rsurface.matrix);
7180         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7181         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7182         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7183         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7184         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7185         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7186         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7187         rsurface.frameblend[0].lerp = 1;
7188         rsurface.ent_alttextures = false;
7189         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7190         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7191         rsurface.entityskeletaltransform3x4 = NULL;
7192         rsurface.entityskeletaltransform3x4buffer = NULL;
7193         rsurface.entityskeletaltransform3x4offset = 0;
7194         rsurface.entityskeletaltransform3x4size = 0;
7195         rsurface.entityskeletalnumtransforms = 0;
7196         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7197         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7198         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7199         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7200         if (wanttangents)
7201         {
7202                 rsurface.modelvertex3f = (float *)vertex3f;
7203                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7204                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7205                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7206         }
7207         else if (wantnormals)
7208         {
7209                 rsurface.modelvertex3f = (float *)vertex3f;
7210                 rsurface.modelsvector3f = NULL;
7211                 rsurface.modeltvector3f = NULL;
7212                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7213         }
7214         else
7215         {
7216                 rsurface.modelvertex3f = (float *)vertex3f;
7217                 rsurface.modelsvector3f = NULL;
7218                 rsurface.modeltvector3f = NULL;
7219                 rsurface.modelnormal3f = NULL;
7220         }
7221         rsurface.modelvertex3f_vertexbuffer = 0;
7222         rsurface.modelvertex3f_bufferoffset = 0;
7223         rsurface.modelsvector3f_vertexbuffer = 0;
7224         rsurface.modelsvector3f_bufferoffset = 0;
7225         rsurface.modeltvector3f_vertexbuffer = 0;
7226         rsurface.modeltvector3f_bufferoffset = 0;
7227         rsurface.modelnormal3f_vertexbuffer = 0;
7228         rsurface.modelnormal3f_bufferoffset = 0;
7229         rsurface.modelgeneratedvertex = true;
7230         rsurface.modellightmapcolor4f  = (float *)color4f;
7231         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7232         rsurface.modellightmapcolor4f_bufferoffset = 0;
7233         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7234         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7235         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7236         rsurface.modeltexcoordlightmap2f  = NULL;
7237         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7238         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7239         rsurface.modelskeletalindex4ub = NULL;
7240         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7241         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7242         rsurface.modelskeletalweight4ub = NULL;
7243         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7244         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7245         rsurface.modelelement3i = (int *)element3i;
7246         rsurface.modelelement3i_indexbuffer = NULL;
7247         rsurface.modelelement3i_bufferoffset = 0;
7248         rsurface.modelelement3s = (unsigned short *)element3s;
7249         rsurface.modelelement3s_indexbuffer = NULL;
7250         rsurface.modelelement3s_bufferoffset = 0;
7251         rsurface.modellightmapoffsets = NULL;
7252         rsurface.modelsurfaces = NULL;
7253         rsurface.batchgeneratedvertex = false;
7254         rsurface.batchfirstvertex = 0;
7255         rsurface.batchnumvertices = 0;
7256         rsurface.batchfirsttriangle = 0;
7257         rsurface.batchnumtriangles = 0;
7258         rsurface.batchvertex3f  = NULL;
7259         rsurface.batchvertex3f_vertexbuffer = NULL;
7260         rsurface.batchvertex3f_bufferoffset = 0;
7261         rsurface.batchsvector3f = NULL;
7262         rsurface.batchsvector3f_vertexbuffer = NULL;
7263         rsurface.batchsvector3f_bufferoffset = 0;
7264         rsurface.batchtvector3f = NULL;
7265         rsurface.batchtvector3f_vertexbuffer = NULL;
7266         rsurface.batchtvector3f_bufferoffset = 0;
7267         rsurface.batchnormal3f  = NULL;
7268         rsurface.batchnormal3f_vertexbuffer = NULL;
7269         rsurface.batchnormal3f_bufferoffset = 0;
7270         rsurface.batchlightmapcolor4f = NULL;
7271         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7272         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7273         rsurface.batchtexcoordtexture2f = NULL;
7274         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7275         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7276         rsurface.batchtexcoordlightmap2f = NULL;
7277         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7278         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7279         rsurface.batchskeletalindex4ub = NULL;
7280         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7281         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7282         rsurface.batchskeletalweight4ub = NULL;
7283         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7284         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7285         rsurface.batchelement3i = NULL;
7286         rsurface.batchelement3i_indexbuffer = NULL;
7287         rsurface.batchelement3i_bufferoffset = 0;
7288         rsurface.batchelement3s = NULL;
7289         rsurface.batchelement3s_indexbuffer = NULL;
7290         rsurface.batchelement3s_bufferoffset = 0;
7291         rsurface.forcecurrenttextureupdate = true;
7292
7293         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7294         {
7295                 if ((wantnormals || wanttangents) && !normal3f)
7296                 {
7297                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7298                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7299                 }
7300                 if (wanttangents && !svector3f)
7301                 {
7302                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7303                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7304                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7305                 }
7306         }
7307 }
7308
7309 float RSurf_FogPoint(const float *v)
7310 {
7311         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7312         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7313         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7314         float FogHeightFade = r_refdef.fogheightfade;
7315         float fogfrac;
7316         unsigned int fogmasktableindex;
7317         if (r_refdef.fogplaneviewabove)
7318                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7319         else
7320                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7321         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7322         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7323 }
7324
7325 float RSurf_FogVertex(const float *v)
7326 {
7327         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7328         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7329         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7330         float FogHeightFade = rsurface.fogheightfade;
7331         float fogfrac;
7332         unsigned int fogmasktableindex;
7333         if (r_refdef.fogplaneviewabove)
7334                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7335         else
7336                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7337         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7338         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7339 }
7340
7341 void RSurf_UploadBuffersForBatch(void)
7342 {
7343         // 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)
7344         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7345         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7346                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7347         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7348                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7349         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7350                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7351         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7352                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7353         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7354                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7355         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7356                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7357         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7358                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7359         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7360                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7361         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7362                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7363
7364         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7365                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7366         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7367                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7368
7369         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7370         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7371         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7372         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7373         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7374         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7375         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7376         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7377         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7378         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7379 }
7380
7381 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7382 {
7383         int i;
7384         for (i = 0;i < numelements;i++)
7385                 outelement3i[i] = inelement3i[i] + adjust;
7386 }
7387
7388 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7389 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7390 {
7391         int deformindex;
7392         int firsttriangle;
7393         int numtriangles;
7394         int firstvertex;
7395         int endvertex;
7396         int numvertices;
7397         int surfacefirsttriangle;
7398         int surfacenumtriangles;
7399         int surfacefirstvertex;
7400         int surfaceendvertex;
7401         int surfacenumvertices;
7402         int batchnumsurfaces = texturenumsurfaces;
7403         int batchnumvertices;
7404         int batchnumtriangles;
7405         int i, j;
7406         qbool gaps;
7407         qbool dynamicvertex;
7408         float amplitude;
7409         float animpos;
7410         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7411         float waveparms[4];
7412         unsigned char *ub;
7413         q3shaderinfo_deform_t *deform;
7414         const msurface_t *surface, *firstsurface;
7415         if (!texturenumsurfaces)
7416                 return;
7417         // find vertex range of this surface batch
7418         gaps = false;
7419         firstsurface = texturesurfacelist[0];
7420         firsttriangle = firstsurface->num_firsttriangle;
7421         batchnumvertices = 0;
7422         batchnumtriangles = 0;
7423         firstvertex = endvertex = firstsurface->num_firstvertex;
7424         for (i = 0;i < texturenumsurfaces;i++)
7425         {
7426                 surface = texturesurfacelist[i];
7427                 if (surface != firstsurface + i)
7428                         gaps = true;
7429                 surfacefirstvertex = surface->num_firstvertex;
7430                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7431                 surfacenumvertices = surface->num_vertices;
7432                 surfacenumtriangles = surface->num_triangles;
7433                 if (firstvertex > surfacefirstvertex)
7434                         firstvertex = surfacefirstvertex;
7435                 if (endvertex < surfaceendvertex)
7436                         endvertex = surfaceendvertex;
7437                 batchnumvertices += surfacenumvertices;
7438                 batchnumtriangles += surfacenumtriangles;
7439         }
7440
7441         r_refdef.stats[r_stat_batch_batches]++;
7442         if (gaps)
7443                 r_refdef.stats[r_stat_batch_withgaps]++;
7444         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7445         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7446         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7447
7448         // we now know the vertex range used, and if there are any gaps in it
7449         rsurface.batchfirstvertex = firstvertex;
7450         rsurface.batchnumvertices = endvertex - firstvertex;
7451         rsurface.batchfirsttriangle = firsttriangle;
7452         rsurface.batchnumtriangles = batchnumtriangles;
7453
7454         // check if any dynamic vertex processing must occur
7455         dynamicvertex = false;
7456
7457         // we must use vertexbuffers for rendering, we can upload vertex buffers
7458         // easily enough but if the basevertex is non-zero it becomes more
7459         // difficult, so force dynamicvertex path in that case - it's suboptimal
7460         // but the most optimal case is to have the geometry sources provide their
7461         // own anyway.
7462         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7463                 dynamicvertex = true;
7464
7465         // a cvar to force the dynamic vertex path to be taken, for debugging
7466         if (r_batch_debugdynamicvertexpath.integer)
7467         {
7468                 if (!dynamicvertex)
7469                 {
7470                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7471                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7472                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7473                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7474                 }
7475                 dynamicvertex = true;
7476         }
7477
7478         // if there is a chance of animated vertex colors, it's a dynamic batch
7479         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7480         {
7481                 if (!dynamicvertex)
7482                 {
7483                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7484                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7485                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7486                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7487                 }
7488                 dynamicvertex = true;
7489         }
7490
7491         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7492         {
7493                 switch (deform->deform)
7494                 {
7495                 default:
7496                 case Q3DEFORM_PROJECTIONSHADOW:
7497                 case Q3DEFORM_TEXT0:
7498                 case Q3DEFORM_TEXT1:
7499                 case Q3DEFORM_TEXT2:
7500                 case Q3DEFORM_TEXT3:
7501                 case Q3DEFORM_TEXT4:
7502                 case Q3DEFORM_TEXT5:
7503                 case Q3DEFORM_TEXT6:
7504                 case Q3DEFORM_TEXT7:
7505                 case Q3DEFORM_NONE:
7506                         break;
7507                 case Q3DEFORM_AUTOSPRITE:
7508                         if (!dynamicvertex)
7509                         {
7510                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7511                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7512                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7513                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7514                         }
7515                         dynamicvertex = true;
7516                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7517                         break;
7518                 case Q3DEFORM_AUTOSPRITE2:
7519                         if (!dynamicvertex)
7520                         {
7521                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7522                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7523                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7524                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7525                         }
7526                         dynamicvertex = true;
7527                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7528                         break;
7529                 case Q3DEFORM_NORMAL:
7530                         if (!dynamicvertex)
7531                         {
7532                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7533                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7534                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7535                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7536                         }
7537                         dynamicvertex = true;
7538                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7539                         break;
7540                 case Q3DEFORM_WAVE:
7541                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7542                                 break; // if wavefunc is a nop, ignore this transform
7543                         if (!dynamicvertex)
7544                         {
7545                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7546                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7547                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7548                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7549                         }
7550                         dynamicvertex = true;
7551                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7552                         break;
7553                 case Q3DEFORM_BULGE:
7554                         if (!dynamicvertex)
7555                         {
7556                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7557                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7558                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7559                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7560                         }
7561                         dynamicvertex = true;
7562                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7563                         break;
7564                 case Q3DEFORM_MOVE:
7565                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7566                                 break; // if wavefunc is a nop, ignore this transform
7567                         if (!dynamicvertex)
7568                         {
7569                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7570                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7571                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7572                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7573                         }
7574                         dynamicvertex = true;
7575                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7576                         break;
7577                 }
7578         }
7579         if (rsurface.texture->materialshaderpass)
7580         {
7581                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7582                 {
7583                 default:
7584                 case Q3TCGEN_TEXTURE:
7585                         break;
7586                 case Q3TCGEN_LIGHTMAP:
7587                         if (!dynamicvertex)
7588                         {
7589                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7590                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7591                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7592                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7593                         }
7594                         dynamicvertex = true;
7595                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7596                         break;
7597                 case Q3TCGEN_VECTOR:
7598                         if (!dynamicvertex)
7599                         {
7600                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7601                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7602                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7603                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7604                         }
7605                         dynamicvertex = true;
7606                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7607                         break;
7608                 case Q3TCGEN_ENVIRONMENT:
7609                         if (!dynamicvertex)
7610                         {
7611                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7612                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7613                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7614                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7615                         }
7616                         dynamicvertex = true;
7617                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7618                         break;
7619                 }
7620                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7621                 {
7622                         if (!dynamicvertex)
7623                         {
7624                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7625                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7626                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7627                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7628                         }
7629                         dynamicvertex = true;
7630                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7631                 }
7632         }
7633
7634         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7635         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7636         // we ensure this by treating the vertex batch as dynamic...
7637         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7638         {
7639                 if (!dynamicvertex)
7640                 {
7641                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7642                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7643                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7644                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7645                 }
7646                 dynamicvertex = true;
7647         }
7648
7649         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7650         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7651                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7652
7653         rsurface.batchvertex3f = rsurface.modelvertex3f;
7654         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7655         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7656         rsurface.batchsvector3f = rsurface.modelsvector3f;
7657         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7658         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7659         rsurface.batchtvector3f = rsurface.modeltvector3f;
7660         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7661         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7662         rsurface.batchnormal3f = rsurface.modelnormal3f;
7663         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7664         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7665         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7666         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7667         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7668         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7669         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7670         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7671         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7672         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7673         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7674         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7675         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7676         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7677         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7678         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7679         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7680         rsurface.batchelement3i = rsurface.modelelement3i;
7681         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7682         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7683         rsurface.batchelement3s = rsurface.modelelement3s;
7684         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7685         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7686         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7687         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7688         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7689         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7690         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7691
7692         // if any dynamic vertex processing has to occur in software, we copy the
7693         // entire surface list together before processing to rebase the vertices
7694         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7695         //
7696         // if any gaps exist and we do not have a static vertex buffer, we have to
7697         // copy the surface list together to avoid wasting upload bandwidth on the
7698         // vertices in the gaps.
7699         //
7700         // if gaps exist and we have a static vertex buffer, we can choose whether
7701         // to combine the index buffer ranges into one dynamic index buffer or
7702         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7703         //
7704         // in many cases the batch is reduced to one draw call.
7705
7706         rsurface.batchmultidraw = false;
7707         rsurface.batchmultidrawnumsurfaces = 0;
7708         rsurface.batchmultidrawsurfacelist = NULL;
7709
7710         if (!dynamicvertex)
7711         {
7712                 // static vertex data, just set pointers...
7713                 rsurface.batchgeneratedvertex = false;
7714                 // if there are gaps, we want to build a combined index buffer,
7715                 // otherwise use the original static buffer with an appropriate offset
7716                 if (gaps)
7717                 {
7718                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7719                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7720                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7721                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7722                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7723                         {
7724                                 rsurface.batchmultidraw = true;
7725                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7726                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7727                                 return;
7728                         }
7729                         // build a new triangle elements array for this batch
7730                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7731                         rsurface.batchfirsttriangle = 0;
7732                         numtriangles = 0;
7733                         for (i = 0;i < texturenumsurfaces;i++)
7734                         {
7735                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7736                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7737                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7738                                 numtriangles += surfacenumtriangles;
7739                         }
7740                         rsurface.batchelement3i_indexbuffer = NULL;
7741                         rsurface.batchelement3i_bufferoffset = 0;
7742                         rsurface.batchelement3s = NULL;
7743                         rsurface.batchelement3s_indexbuffer = NULL;
7744                         rsurface.batchelement3s_bufferoffset = 0;
7745                         if (endvertex <= 65536)
7746                         {
7747                                 // make a 16bit (unsigned short) index array if possible
7748                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7749                                 for (i = 0;i < numtriangles*3;i++)
7750                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7751                         }
7752                 }
7753                 else
7754                 {
7755                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7756                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7757                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7758                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7759                 }
7760                 return;
7761         }
7762
7763         // something needs software processing, do it for real...
7764         // we only directly handle separate array data in this case and then
7765         // generate interleaved data if needed...
7766         rsurface.batchgeneratedvertex = true;
7767         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7768         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7769         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7770         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7771
7772         // now copy the vertex data into a combined array and make an index array
7773         // (this is what Quake3 does all the time)
7774         // we also apply any skeletal animation here that would have been done in
7775         // the vertex shader, because most of the dynamic vertex animation cases
7776         // need actual vertex positions and normals
7777         //if (dynamicvertex)
7778         {
7779                 rsurface.batchvertex3f = NULL;
7780                 rsurface.batchvertex3f_vertexbuffer = NULL;
7781                 rsurface.batchvertex3f_bufferoffset = 0;
7782                 rsurface.batchsvector3f = NULL;
7783                 rsurface.batchsvector3f_vertexbuffer = NULL;
7784                 rsurface.batchsvector3f_bufferoffset = 0;
7785                 rsurface.batchtvector3f = NULL;
7786                 rsurface.batchtvector3f_vertexbuffer = NULL;
7787                 rsurface.batchtvector3f_bufferoffset = 0;
7788                 rsurface.batchnormal3f = NULL;
7789                 rsurface.batchnormal3f_vertexbuffer = NULL;
7790                 rsurface.batchnormal3f_bufferoffset = 0;
7791                 rsurface.batchlightmapcolor4f = NULL;
7792                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7793                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7794                 rsurface.batchtexcoordtexture2f = NULL;
7795                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7796                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7797                 rsurface.batchtexcoordlightmap2f = NULL;
7798                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7799                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7800                 rsurface.batchskeletalindex4ub = NULL;
7801                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7802                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7803                 rsurface.batchskeletalweight4ub = NULL;
7804                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7805                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7806                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7807                 rsurface.batchelement3i_indexbuffer = NULL;
7808                 rsurface.batchelement3i_bufferoffset = 0;
7809                 rsurface.batchelement3s = NULL;
7810                 rsurface.batchelement3s_indexbuffer = NULL;
7811                 rsurface.batchelement3s_bufferoffset = 0;
7812                 rsurface.batchskeletaltransform3x4buffer = NULL;
7813                 rsurface.batchskeletaltransform3x4offset = 0;
7814                 rsurface.batchskeletaltransform3x4size = 0;
7815                 // we'll only be setting up certain arrays as needed
7816                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7817                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7818                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7819                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7820                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7821                 {
7822                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7823                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7824                 }
7825                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7826                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7827                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7828                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7829                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7830                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7831                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7832                 {
7833                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7834                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7835                 }
7836                 numvertices = 0;
7837                 numtriangles = 0;
7838                 for (i = 0;i < texturenumsurfaces;i++)
7839                 {
7840                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7841                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7842                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7843                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7844                         // copy only the data requested
7845                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7846                         {
7847                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7848                                 {
7849                                         if (rsurface.batchvertex3f)
7850                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7851                                         else
7852                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7853                                 }
7854                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7855                                 {
7856                                         if (rsurface.modelnormal3f)
7857                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7858                                         else
7859                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7860                                 }
7861                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7862                                 {
7863                                         if (rsurface.modelsvector3f)
7864                                         {
7865                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7866                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7867                                         }
7868                                         else
7869                                         {
7870                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7871                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7872                                         }
7873                                 }
7874                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7875                                 {
7876                                         if (rsurface.modellightmapcolor4f)
7877                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7878                                         else
7879                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7880                                 }
7881                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7882                                 {
7883                                         if (rsurface.modeltexcoordtexture2f)
7884                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7885                                         else
7886                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7887                                 }
7888                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7889                                 {
7890                                         if (rsurface.modeltexcoordlightmap2f)
7891                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7892                                         else
7893                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7894                                 }
7895                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7896                                 {
7897                                         if (rsurface.modelskeletalindex4ub)
7898                                         {
7899                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7900                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7901                                         }
7902                                         else
7903                                         {
7904                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7905                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7906                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7907                                                 for (j = 0;j < surfacenumvertices;j++)
7908                                                         ub[j*4] = 255;
7909                                         }
7910                                 }
7911                         }
7912                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7913                         numvertices += surfacenumvertices;
7914                         numtriangles += surfacenumtriangles;
7915                 }
7916
7917                 // generate a 16bit index array as well if possible
7918                 // (in general, dynamic batches fit)
7919                 if (numvertices <= 65536)
7920                 {
7921                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7922                         for (i = 0;i < numtriangles*3;i++)
7923                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7924                 }
7925
7926                 // since we've copied everything, the batch now starts at 0
7927                 rsurface.batchfirstvertex = 0;
7928                 rsurface.batchnumvertices = batchnumvertices;
7929                 rsurface.batchfirsttriangle = 0;
7930                 rsurface.batchnumtriangles = batchnumtriangles;
7931         }
7932
7933         // apply skeletal animation that would have been done in the vertex shader
7934         if (rsurface.batchskeletaltransform3x4)
7935         {
7936                 const unsigned char *si;
7937                 const unsigned char *sw;
7938                 const float *t[4];
7939                 const float *b = rsurface.batchskeletaltransform3x4;
7940                 float *vp, *vs, *vt, *vn;
7941                 float w[4];
7942                 float m[3][4], n[3][4];
7943                 float tp[3], ts[3], tt[3], tn[3];
7944                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7945                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7946                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7947                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7948                 si = rsurface.batchskeletalindex4ub;
7949                 sw = rsurface.batchskeletalweight4ub;
7950                 vp = rsurface.batchvertex3f;
7951                 vs = rsurface.batchsvector3f;
7952                 vt = rsurface.batchtvector3f;
7953                 vn = rsurface.batchnormal3f;
7954                 memset(m[0], 0, sizeof(m));
7955                 memset(n[0], 0, sizeof(n));
7956                 for (i = 0;i < batchnumvertices;i++)
7957                 {
7958                         t[0] = b + si[0]*12;
7959                         if (sw[0] == 255)
7960                         {
7961                                 // common case - only one matrix
7962                                 m[0][0] = t[0][ 0];
7963                                 m[0][1] = t[0][ 1];
7964                                 m[0][2] = t[0][ 2];
7965                                 m[0][3] = t[0][ 3];
7966                                 m[1][0] = t[0][ 4];
7967                                 m[1][1] = t[0][ 5];
7968                                 m[1][2] = t[0][ 6];
7969                                 m[1][3] = t[0][ 7];
7970                                 m[2][0] = t[0][ 8];
7971                                 m[2][1] = t[0][ 9];
7972                                 m[2][2] = t[0][10];
7973                                 m[2][3] = t[0][11];
7974                         }
7975                         else if (sw[2] + sw[3])
7976                         {
7977                                 // blend 4 matrices
7978                                 t[1] = b + si[1]*12;
7979                                 t[2] = b + si[2]*12;
7980                                 t[3] = b + si[3]*12;
7981                                 w[0] = sw[0] * (1.0f / 255.0f);
7982                                 w[1] = sw[1] * (1.0f / 255.0f);
7983                                 w[2] = sw[2] * (1.0f / 255.0f);
7984                                 w[3] = sw[3] * (1.0f / 255.0f);
7985                                 // blend the matrices
7986                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7987                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7988                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7989                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7990                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7991                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7992                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7993                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7994                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7995                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7996                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7997                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
7998                         }
7999                         else
8000                         {
8001                                 // blend 2 matrices
8002                                 t[1] = b + si[1]*12;
8003                                 w[0] = sw[0] * (1.0f / 255.0f);
8004                                 w[1] = sw[1] * (1.0f / 255.0f);
8005                                 // blend the matrices
8006                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8007                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8008                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8009                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8010                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8011                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8012                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8013                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8014                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8015                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8016                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8017                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8018                         }
8019                         si += 4;
8020                         sw += 4;
8021                         // modify the vertex
8022                         VectorCopy(vp, tp);
8023                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8024                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8025                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8026                         vp += 3;
8027                         if (vn)
8028                         {
8029                                 // the normal transformation matrix is a set of cross products...
8030                                 CrossProduct(m[1], m[2], n[0]);
8031                                 CrossProduct(m[2], m[0], n[1]);
8032                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8033                                 VectorCopy(vn, tn);
8034                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8035                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8036                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8037                                 VectorNormalize(vn);
8038                                 vn += 3;
8039                                 if (vs)
8040                                 {
8041                                         VectorCopy(vs, ts);
8042                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8043                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8044                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8045                                         VectorNormalize(vs);
8046                                         vs += 3;
8047                                         VectorCopy(vt, tt);
8048                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8049                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8050                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8051                                         VectorNormalize(vt);
8052                                         vt += 3;
8053                                 }
8054                         }
8055                 }
8056                 rsurface.batchskeletaltransform3x4 = NULL;
8057                 rsurface.batchskeletalnumtransforms = 0;
8058         }
8059
8060         // q1bsp surfaces rendered in vertex color mode have to have colors
8061         // calculated based on lightstyles
8062         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8063         {
8064                 // generate color arrays for the surfaces in this list
8065                 int c[4];
8066                 int scale;
8067                 int size3;
8068                 const int *offsets;
8069                 const unsigned char *lm;
8070                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8071                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8072                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8073                 numvertices = 0;
8074                 for (i = 0;i < texturenumsurfaces;i++)
8075                 {
8076                         surface = texturesurfacelist[i];
8077                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8078                         surfacenumvertices = surface->num_vertices;
8079                         if (surface->lightmapinfo->samples)
8080                         {
8081                                 for (j = 0;j < surfacenumvertices;j++)
8082                                 {
8083                                         lm = surface->lightmapinfo->samples + offsets[j];
8084                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8085                                         VectorScale(lm, scale, c);
8086                                         if (surface->lightmapinfo->styles[1] != 255)
8087                                         {
8088                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8089                                                 lm += size3;
8090                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8091                                                 VectorMA(c, scale, lm, c);
8092                                                 if (surface->lightmapinfo->styles[2] != 255)
8093                                                 {
8094                                                         lm += size3;
8095                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8096                                                         VectorMA(c, scale, lm, c);
8097                                                         if (surface->lightmapinfo->styles[3] != 255)
8098                                                         {
8099                                                                 lm += size3;
8100                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8101                                                                 VectorMA(c, scale, lm, c);
8102                                                         }
8103                                                 }
8104                                         }
8105                                         c[0] >>= 7;
8106                                         c[1] >>= 7;
8107                                         c[2] >>= 7;
8108                                         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);
8109                                         numvertices++;
8110                                 }
8111                         }
8112                         else
8113                         {
8114                                 for (j = 0;j < surfacenumvertices;j++)
8115                                 {
8116                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8117                                         numvertices++;
8118                                 }
8119                         }
8120                 }
8121         }
8122
8123         // if vertices are deformed (sprite flares and things in maps, possibly
8124         // water waves, bulges and other deformations), modify the copied vertices
8125         // in place
8126         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8127         {
8128                 float scale;
8129                 switch (deform->deform)
8130                 {
8131                 default:
8132                 case Q3DEFORM_PROJECTIONSHADOW:
8133                 case Q3DEFORM_TEXT0:
8134                 case Q3DEFORM_TEXT1:
8135                 case Q3DEFORM_TEXT2:
8136                 case Q3DEFORM_TEXT3:
8137                 case Q3DEFORM_TEXT4:
8138                 case Q3DEFORM_TEXT5:
8139                 case Q3DEFORM_TEXT6:
8140                 case Q3DEFORM_TEXT7:
8141                 case Q3DEFORM_NONE:
8142                         break;
8143                 case Q3DEFORM_AUTOSPRITE:
8144                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8145                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8146                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8147                         VectorNormalize(newforward);
8148                         VectorNormalize(newright);
8149                         VectorNormalize(newup);
8150 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8151 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8152 //                      rsurface.batchvertex3f_bufferoffset = 0;
8153 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8154 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8155 //                      rsurface.batchsvector3f_bufferoffset = 0;
8156 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8157 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8158 //                      rsurface.batchtvector3f_bufferoffset = 0;
8159 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8160 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8161 //                      rsurface.batchnormal3f_bufferoffset = 0;
8162                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8163                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8164                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8165                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8166                                 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);
8167                         // a single autosprite surface can contain multiple sprites...
8168                         for (j = 0;j < batchnumvertices - 3;j += 4)
8169                         {
8170                                 VectorClear(center);
8171                                 for (i = 0;i < 4;i++)
8172                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8173                                 VectorScale(center, 0.25f, center);
8174                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8175                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8176                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8177                                 for (i = 0;i < 4;i++)
8178                                 {
8179                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8180                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8181                                 }
8182                         }
8183                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8184                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8185                         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);
8186                         break;
8187                 case Q3DEFORM_AUTOSPRITE2:
8188                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8189                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8190                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8191                         VectorNormalize(newforward);
8192                         VectorNormalize(newright);
8193                         VectorNormalize(newup);
8194 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8195 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8196 //                      rsurface.batchvertex3f_bufferoffset = 0;
8197                         {
8198                                 const float *v1, *v2;
8199                                 vec3_t start, end;
8200                                 float f, l;
8201                                 struct
8202                                 {
8203                                         float length2;
8204                                         const float *v1;
8205                                         const float *v2;
8206                                 }
8207                                 shortest[2];
8208                                 memset(shortest, 0, sizeof(shortest));
8209                                 // a single autosprite surface can contain multiple sprites...
8210                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8211                                 {
8212                                         VectorClear(center);
8213                                         for (i = 0;i < 4;i++)
8214                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8215                                         VectorScale(center, 0.25f, center);
8216                                         // find the two shortest edges, then use them to define the
8217                                         // axis vectors for rotating around the central axis
8218                                         for (i = 0;i < 6;i++)
8219                                         {
8220                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8221                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8222                                                 l = VectorDistance2(v1, v2);
8223                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8224                                                 if (v1[2] != v2[2])
8225                                                         l += (1.0f / 1024.0f);
8226                                                 if (shortest[0].length2 > l || i == 0)
8227                                                 {
8228                                                         shortest[1] = shortest[0];
8229                                                         shortest[0].length2 = l;
8230                                                         shortest[0].v1 = v1;
8231                                                         shortest[0].v2 = v2;
8232                                                 }
8233                                                 else if (shortest[1].length2 > l || i == 1)
8234                                                 {
8235                                                         shortest[1].length2 = l;
8236                                                         shortest[1].v1 = v1;
8237                                                         shortest[1].v2 = v2;
8238                                                 }
8239                                         }
8240                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8241                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8242                                         // this calculates the right vector from the shortest edge
8243                                         // and the up vector from the edge midpoints
8244                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8245                                         VectorNormalize(right);
8246                                         VectorSubtract(end, start, up);
8247                                         VectorNormalize(up);
8248                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8249                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8250                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8251                                         VectorNegate(forward, forward);
8252                                         VectorReflect(forward, 0, up, forward);
8253                                         VectorNormalize(forward);
8254                                         CrossProduct(up, forward, newright);
8255                                         VectorNormalize(newright);
8256                                         // rotate the quad around the up axis vector, this is made
8257                                         // especially easy by the fact we know the quad is flat,
8258                                         // so we only have to subtract the center position and
8259                                         // measure distance along the right vector, and then
8260                                         // multiply that by the newright vector and add back the
8261                                         // center position
8262                                         // we also need to subtract the old position to undo the
8263                                         // displacement from the center, which we do with a
8264                                         // DotProduct, the subtraction/addition of center is also
8265                                         // optimized into DotProducts here
8266                                         l = DotProduct(right, center);
8267                                         for (i = 0;i < 4;i++)
8268                                         {
8269                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8270                                                 f = DotProduct(right, v1) - l;
8271                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8272                                         }
8273                                 }
8274                         }
8275                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8276                         {
8277 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8278 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8279 //                              rsurface.batchnormal3f_bufferoffset = 0;
8280                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8281                         }
8282                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8283                         {
8284 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8285 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8286 //                              rsurface.batchsvector3f_bufferoffset = 0;
8287 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8288 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8289 //                              rsurface.batchtvector3f_bufferoffset = 0;
8290                                 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);
8291                         }
8292                         break;
8293                 case Q3DEFORM_NORMAL:
8294                         // deform the normals to make reflections wavey
8295                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8296                         rsurface.batchnormal3f_vertexbuffer = NULL;
8297                         rsurface.batchnormal3f_bufferoffset = 0;
8298                         for (j = 0;j < batchnumvertices;j++)
8299                         {
8300                                 float vertex[3];
8301                                 float *normal = rsurface.batchnormal3f + 3*j;
8302                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8303                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8304                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8305                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8306                                 VectorNormalize(normal);
8307                         }
8308                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8309                         {
8310 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8311 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8312 //                              rsurface.batchsvector3f_bufferoffset = 0;
8313 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8314 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8315 //                              rsurface.batchtvector3f_bufferoffset = 0;
8316                                 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);
8317                         }
8318                         break;
8319                 case Q3DEFORM_WAVE:
8320                         // deform vertex array to make wavey water and flags and such
8321                         waveparms[0] = deform->waveparms[0];
8322                         waveparms[1] = deform->waveparms[1];
8323                         waveparms[2] = deform->waveparms[2];
8324                         waveparms[3] = deform->waveparms[3];
8325                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8326                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8327                         // this is how a divisor of vertex influence on deformation
8328                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8329                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8330 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8331 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8332 //                      rsurface.batchvertex3f_bufferoffset = 0;
8333 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8334 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8335 //                      rsurface.batchnormal3f_bufferoffset = 0;
8336                         for (j = 0;j < batchnumvertices;j++)
8337                         {
8338                                 // if the wavefunc depends on time, evaluate it per-vertex
8339                                 if (waveparms[3])
8340                                 {
8341                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8342                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8343                                 }
8344                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8345                         }
8346                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8347                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8348                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8349                         {
8350 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8351 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8352 //                              rsurface.batchsvector3f_bufferoffset = 0;
8353 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8354 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8355 //                              rsurface.batchtvector3f_bufferoffset = 0;
8356                                 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);
8357                         }
8358                         break;
8359                 case Q3DEFORM_BULGE:
8360                         // deform vertex array to make the surface have moving bulges
8361 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8362 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8363 //                      rsurface.batchvertex3f_bufferoffset = 0;
8364 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8365 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8366 //                      rsurface.batchnormal3f_bufferoffset = 0;
8367                         for (j = 0;j < batchnumvertices;j++)
8368                         {
8369                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8370                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8371                         }
8372                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8373                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8374                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8375                         {
8376 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8377 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8378 //                              rsurface.batchsvector3f_bufferoffset = 0;
8379 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8380 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8381 //                              rsurface.batchtvector3f_bufferoffset = 0;
8382                                 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);
8383                         }
8384                         break;
8385                 case Q3DEFORM_MOVE:
8386                         // deform vertex array
8387                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8388                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8389                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8390                         VectorScale(deform->parms, scale, waveparms);
8391 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8392 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8393 //                      rsurface.batchvertex3f_bufferoffset = 0;
8394                         for (j = 0;j < batchnumvertices;j++)
8395                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8396                         break;
8397                 }
8398         }
8399
8400         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8401         {
8402         // generate texcoords based on the chosen texcoord source
8403                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8404                 {
8405                 default:
8406                 case Q3TCGEN_TEXTURE:
8407                         break;
8408                 case Q3TCGEN_LIGHTMAP:
8409         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8410         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8411         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8412                         if (rsurface.batchtexcoordlightmap2f)
8413                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8414                         break;
8415                 case Q3TCGEN_VECTOR:
8416         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8417         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8418         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8419                         for (j = 0;j < batchnumvertices;j++)
8420                         {
8421                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8422                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8423                         }
8424                         break;
8425                 case Q3TCGEN_ENVIRONMENT:
8426                         // make environment reflections using a spheremap
8427                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8428                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8429                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8430                         for (j = 0;j < batchnumvertices;j++)
8431                         {
8432                                 // identical to Q3A's method, but executed in worldspace so
8433                                 // carried models can be shiny too
8434
8435                                 float viewer[3], d, reflected[3], worldreflected[3];
8436
8437                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8438                                 // VectorNormalize(viewer);
8439
8440                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8441
8442                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8443                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8444                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8445                                 // note: this is proportinal to viewer, so we can normalize later
8446
8447                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8448                                 VectorNormalize(worldreflected);
8449
8450                                 // note: this sphere map only uses world x and z!
8451                                 // so positive and negative y will LOOK THE SAME.
8452                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8453                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8454                         }
8455                         break;
8456                 }
8457                 // the only tcmod that needs software vertex processing is turbulent, so
8458                 // check for it here and apply the changes if needed
8459                 // and we only support that as the first one
8460                 // (handling a mixture of turbulent and other tcmods would be problematic
8461                 //  without punting it entirely to a software path)
8462                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8463                 {
8464                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8465                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8466         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8467         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8468         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8469                         for (j = 0;j < batchnumvertices;j++)
8470                         {
8471                                 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);
8472                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8473                         }
8474                 }
8475         }
8476 }
8477
8478 void RSurf_DrawBatch(void)
8479 {
8480         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8481         // through the pipeline, killing it earlier in the pipeline would have
8482         // per-surface overhead rather than per-batch overhead, so it's best to
8483         // reject it here, before it hits glDraw.
8484         if (rsurface.batchnumtriangles == 0)
8485                 return;
8486 #if 0
8487         // batch debugging code
8488         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8489         {
8490                 int i;
8491                 int j;
8492                 int c;
8493                 const int *e;
8494                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8495                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8496                 {
8497                         c = e[i];
8498                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8499                         {
8500                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8501                                 {
8502                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8503                                                 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);
8504                                         break;
8505                                 }
8506                         }
8507                 }
8508         }
8509 #endif
8510         if (rsurface.batchmultidraw)
8511         {
8512                 // issue multiple draws rather than copying index data
8513                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8514                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8515                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8516                 for (i = 0;i < numsurfaces;)
8517                 {
8518                         // combine consecutive surfaces as one draw
8519                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8520                                 if (surfacelist[j] != surfacelist[k] + 1)
8521                                         break;
8522                         firstvertex = surfacelist[i]->num_firstvertex;
8523                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8524                         firsttriangle = surfacelist[i]->num_firsttriangle;
8525                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8526                         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);
8527                         i = j;
8528                 }
8529         }
8530         else
8531         {
8532                 // there is only one consecutive run of index data (may have been combined)
8533                 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);
8534         }
8535 }
8536
8537 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8538 {
8539         // pick the closest matching water plane
8540         int planeindex, vertexindex, bestplaneindex = -1;
8541         float d, bestd;
8542         vec3_t vert;
8543         const float *v;
8544         r_waterstate_waterplane_t *p;
8545         qbool prepared = false;
8546         bestd = 0;
8547         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8548         {
8549                 if(p->camera_entity != rsurface.texture->camera_entity)
8550                         continue;
8551                 d = 0;
8552                 if(!prepared)
8553                 {
8554                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8555                         prepared = true;
8556                         if(rsurface.batchnumvertices == 0)
8557                                 break;
8558                 }
8559                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8560                 {
8561                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8562                         d += fabs(PlaneDiff(vert, &p->plane));
8563                 }
8564                 if (bestd > d || bestplaneindex < 0)
8565                 {
8566                         bestd = d;
8567                         bestplaneindex = planeindex;
8568                 }
8569         }
8570         return bestplaneindex;
8571         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8572         // this situation though, as it might be better to render single larger
8573         // batches with useless stuff (backface culled for example) than to
8574         // render multiple smaller batches
8575 }
8576
8577 void RSurf_SetupDepthAndCulling(void)
8578 {
8579         // submodels are biased to avoid z-fighting with world surfaces that they
8580         // may be exactly overlapping (avoids z-fighting artifacts on certain
8581         // doors and things in Quake maps)
8582         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8583         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8584         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8585         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8586 }
8587
8588 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8589 {
8590         int j;
8591         const float *v;
8592         float p[3], mins[3], maxs[3];
8593         int scissor[4];
8594         // transparent sky would be ridiculous
8595         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8596                 return;
8597         R_SetupShader_Generic_NoTexture(false, false);
8598         skyrenderlater = true;
8599         RSurf_SetupDepthAndCulling();
8600         GL_DepthMask(true);
8601
8602         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8603         if (r_sky_scissor.integer)
8604         {
8605                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8606                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8607                 {
8608                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8609                         if (j > 0)
8610                         {
8611                                 if (mins[0] > p[0]) mins[0] = p[0];
8612                                 if (mins[1] > p[1]) mins[1] = p[1];
8613                                 if (mins[2] > p[2]) mins[2] = p[2];
8614                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8615                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8616                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8617                         }
8618                         else
8619                         {
8620                                 VectorCopy(p, mins);
8621                                 VectorCopy(p, maxs);
8622                         }
8623                 }
8624                 if (!R_ScissorForBBox(mins, maxs, scissor))
8625                 {
8626                         if (skyscissor[2])
8627                         {
8628                                 if (skyscissor[0] > scissor[0])
8629                                 {
8630                                         skyscissor[2] += skyscissor[0] - scissor[0];
8631                                         skyscissor[0] = scissor[0];
8632                                 }
8633                                 if (skyscissor[1] > scissor[1])
8634                                 {
8635                                         skyscissor[3] += skyscissor[1] - scissor[1];
8636                                         skyscissor[1] = scissor[1];
8637                                 }
8638                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8639                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8640                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8641                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8642                         }
8643                         else
8644                                 Vector4Copy(scissor, skyscissor);
8645                 }
8646         }
8647
8648         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8649         // skymasking on them, and Quake3 never did sky masking (unlike
8650         // software Quake and software Quake2), so disable the sky masking
8651         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8652         // and skymasking also looks very bad when noclipping outside the
8653         // level, so don't use it then either.
8654         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)
8655         {
8656                 R_Mesh_ResetTextureState();
8657                 if (skyrendermasked)
8658                 {
8659                         R_SetupShader_DepthOrShadow(false, false, false);
8660                         // depth-only (masking)
8661                         GL_ColorMask(0, 0, 0, 0);
8662                         // just to make sure that braindead drivers don't draw
8663                         // anything despite that colormask...
8664                         GL_BlendFunc(GL_ZERO, GL_ONE);
8665                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8666                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8667                 }
8668                 else
8669                 {
8670                         R_SetupShader_Generic_NoTexture(false, false);
8671                         // fog sky
8672                         GL_BlendFunc(GL_ONE, GL_ZERO);
8673                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8674                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8675                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8676                 }
8677                 RSurf_DrawBatch();
8678                 if (skyrendermasked)
8679                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8680         }
8681         R_Mesh_ResetTextureState();
8682         GL_Color(1, 1, 1, 1);
8683 }
8684
8685 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8686 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8687 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8688 {
8689         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8690                 return;
8691         if (prepass)
8692         {
8693                 // render screenspace normalmap to texture
8694                 GL_DepthMask(true);
8695                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8696                 RSurf_DrawBatch();
8697                 return;
8698         }
8699
8700         // bind lightmap texture
8701
8702         // water/refraction/reflection/camera surfaces have to be handled specially
8703         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8704         {
8705                 int start, end, startplaneindex;
8706                 for (start = 0;start < texturenumsurfaces;start = end)
8707                 {
8708                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8709                         if(startplaneindex < 0)
8710                         {
8711                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8712                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8713                                 end = start + 1;
8714                                 continue;
8715                         }
8716                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8717                                 ;
8718                         // now that we have a batch using the same planeindex, render it
8719                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8720                         {
8721                                 // render water or distortion background
8722                                 GL_DepthMask(true);
8723                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8724                                 RSurf_DrawBatch();
8725                                 // blend surface on top
8726                                 GL_DepthMask(false);
8727                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8728                                 RSurf_DrawBatch();
8729                         }
8730                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8731                         {
8732                                 // render surface with reflection texture as input
8733                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8734                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8735                                 RSurf_DrawBatch();
8736                         }
8737                 }
8738                 return;
8739         }
8740
8741         // render surface batch normally
8742         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8743         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8744         RSurf_DrawBatch();
8745 }
8746
8747 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8748 {
8749         int vi;
8750         int j;
8751         int texturesurfaceindex;
8752         int k;
8753         const msurface_t *surface;
8754         float surfacecolor4f[4];
8755
8756 //      R_Mesh_ResetTextureState();
8757         R_SetupShader_Generic_NoTexture(false, false);
8758
8759         GL_BlendFunc(GL_ONE, GL_ZERO);
8760         GL_DepthMask(writedepth);
8761
8762         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8763         vi = 0;
8764         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8765         {
8766                 surface = texturesurfacelist[texturesurfaceindex];
8767                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8768                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8769                 for (j = 0;j < surface->num_vertices;j++)
8770                 {
8771                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8772                         vi++;
8773                 }
8774         }
8775         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8776         RSurf_DrawBatch();
8777 }
8778
8779 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8780 {
8781         CHECKGLERROR
8782         RSurf_SetupDepthAndCulling();
8783         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8784         {
8785                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8786                 return;
8787         }
8788         switch (vid.renderpath)
8789         {
8790         case RENDERPATH_GL32:
8791         case RENDERPATH_GLES2:
8792                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8793                 break;
8794         }
8795         CHECKGLERROR
8796 }
8797
8798 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8799 {
8800         int i, j;
8801         int texturenumsurfaces, endsurface;
8802         texture_t *texture;
8803         const msurface_t *surface;
8804         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8805
8806         RSurf_ActiveModelEntity(ent, true, true, false);
8807
8808         if (r_transparentdepthmasking.integer)
8809         {
8810                 qbool setup = false;
8811                 for (i = 0;i < numsurfaces;i = j)
8812                 {
8813                         j = i + 1;
8814                         surface = rsurface.modelsurfaces + surfacelist[i];
8815                         texture = surface->texture;
8816                         rsurface.texture = R_GetCurrentTexture(texture);
8817                         rsurface.lightmaptexture = NULL;
8818                         rsurface.deluxemaptexture = NULL;
8819                         rsurface.uselightmaptexture = false;
8820                         // scan ahead until we find a different texture
8821                         endsurface = min(i + 1024, numsurfaces);
8822                         texturenumsurfaces = 0;
8823                         texturesurfacelist[texturenumsurfaces++] = surface;
8824                         for (;j < endsurface;j++)
8825                         {
8826                                 surface = rsurface.modelsurfaces + surfacelist[j];
8827                                 if (texture != surface->texture)
8828                                         break;
8829                                 texturesurfacelist[texturenumsurfaces++] = surface;
8830                         }
8831                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8832                                 continue;
8833                         // render the range of surfaces as depth
8834                         if (!setup)
8835                         {
8836                                 setup = true;
8837                                 GL_ColorMask(0,0,0,0);
8838                                 GL_Color(1,1,1,1);
8839                                 GL_DepthTest(true);
8840                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8841                                 GL_DepthMask(true);
8842 //                              R_Mesh_ResetTextureState();
8843                         }
8844                         RSurf_SetupDepthAndCulling();
8845                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8846                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8847                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8848                         RSurf_DrawBatch();
8849                 }
8850                 if (setup)
8851                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8852         }
8853
8854         for (i = 0;i < numsurfaces;i = j)
8855         {
8856                 j = i + 1;
8857                 surface = rsurface.modelsurfaces + surfacelist[i];
8858                 texture = surface->texture;
8859                 rsurface.texture = R_GetCurrentTexture(texture);
8860                 // scan ahead until we find a different texture
8861                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8862                 texturenumsurfaces = 0;
8863                 texturesurfacelist[texturenumsurfaces++] = surface;
8864                         rsurface.lightmaptexture = surface->lightmaptexture;
8865                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8866                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8867                         for (;j < endsurface;j++)
8868                         {
8869                                 surface = rsurface.modelsurfaces + surfacelist[j];
8870                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8871                                         break;
8872                                 texturesurfacelist[texturenumsurfaces++] = surface;
8873                         }
8874                 // render the range of surfaces
8875                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8876         }
8877         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8878 }
8879
8880 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8881 {
8882         // transparent surfaces get pushed off into the transparent queue
8883         int surfacelistindex;
8884         const msurface_t *surface;
8885         vec3_t tempcenter, center;
8886         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8887         {
8888                 surface = texturesurfacelist[surfacelistindex];
8889                 if (r_transparent_sortsurfacesbynearest.integer)
8890                 {
8891                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8892                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8893                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8894                 }
8895                 else
8896                 {
8897                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8898                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8899                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8900                 }
8901                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8902                 if (rsurface.entity->transparent_offset) // transparent offset
8903                 {
8904                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8905                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8906                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8907                 }
8908                 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);
8909         }
8910 }
8911
8912 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8913 {
8914         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8915                 return;
8916         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8917                 return;
8918         RSurf_SetupDepthAndCulling();
8919         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8920         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8921         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8922         RSurf_DrawBatch();
8923 }
8924
8925 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8926 {
8927         CHECKGLERROR
8928         if (ui)
8929                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8930         else if (depthonly)
8931                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8932         else if (prepass)
8933         {
8934                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8935                         return;
8936                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8937                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8938                 else
8939                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8940         }
8941         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8942                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8943         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8944                 return;
8945         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8946         {
8947                 // in the deferred case, transparent surfaces were queued during prepass
8948                 if (!r_shadow_usingdeferredprepass)
8949                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8950         }
8951         else
8952         {
8953                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8954                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8955         }
8956         CHECKGLERROR
8957 }
8958
8959 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8960 {
8961         int i, j;
8962         texture_t *texture;
8963         R_FrameData_SetMark();
8964         // break the surface list down into batches by texture and use of lightmapping
8965         for (i = 0;i < numsurfaces;i = j)
8966         {
8967                 j = i + 1;
8968                 // texture is the base texture pointer, rsurface.texture is the
8969                 // current frame/skin the texture is directing us to use (for example
8970                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8971                 // use skin 1 instead)
8972                 texture = surfacelist[i]->texture;
8973                 rsurface.texture = R_GetCurrentTexture(texture);
8974                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8975                 {
8976                         // if this texture is not the kind we want, skip ahead to the next one
8977                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8978                                 ;
8979                         continue;
8980                 }
8981                 if(depthonly || prepass)
8982                 {
8983                         rsurface.lightmaptexture = NULL;
8984                         rsurface.deluxemaptexture = NULL;
8985                         rsurface.uselightmaptexture = false;
8986                         // simply scan ahead until we find a different texture or lightmap state
8987                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8988                                 ;
8989                 }
8990                 else
8991                 {
8992                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8993                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8994                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8995                         // simply scan ahead until we find a different texture or lightmap state
8996                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8997                                 ;
8998                 }
8999                 // render the range of surfaces
9000                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9001         }
9002         R_FrameData_ReturnToMark();
9003 }
9004
9005 float locboxvertex3f[6*4*3] =
9006 {
9007         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9008         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9009         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9010         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9011         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9012         1,0,0, 0,0,0, 0,1,0, 1,1,0
9013 };
9014
9015 unsigned short locboxelements[6*2*3] =
9016 {
9017          0, 1, 2, 0, 2, 3,
9018          4, 5, 6, 4, 6, 7,
9019          8, 9,10, 8,10,11,
9020         12,13,14, 12,14,15,
9021         16,17,18, 16,18,19,
9022         20,21,22, 20,22,23
9023 };
9024
9025 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9026 {
9027         int i, j;
9028         cl_locnode_t *loc = (cl_locnode_t *)ent;
9029         vec3_t mins, size;
9030         float vertex3f[6*4*3];
9031         CHECKGLERROR
9032         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9033         GL_DepthMask(false);
9034         GL_DepthRange(0, 1);
9035         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9036         GL_DepthTest(true);
9037         GL_CullFace(GL_NONE);
9038         R_EntityMatrix(&identitymatrix);
9039
9040 //      R_Mesh_ResetTextureState();
9041
9042         i = surfacelist[0];
9043         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9044                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9045                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9046                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9047
9048         if (VectorCompare(loc->mins, loc->maxs))
9049         {
9050                 VectorSet(size, 2, 2, 2);
9051                 VectorMA(loc->mins, -0.5f, size, mins);
9052         }
9053         else
9054         {
9055                 VectorCopy(loc->mins, mins);
9056                 VectorSubtract(loc->maxs, loc->mins, size);
9057         }
9058
9059         for (i = 0;i < 6*4*3;)
9060                 for (j = 0;j < 3;j++, i++)
9061                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9062
9063         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9064         R_SetupShader_Generic_NoTexture(false, false);
9065         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9066 }
9067
9068 void R_DrawLocs(void)
9069 {
9070         int index;
9071         cl_locnode_t *loc, *nearestloc;
9072         vec3_t center;
9073         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9074         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9075         {
9076                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9077                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9078         }
9079 }
9080
9081 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9082 {
9083         if (decalsystem->decals)
9084                 Mem_Free(decalsystem->decals);
9085         memset(decalsystem, 0, sizeof(*decalsystem));
9086 }
9087
9088 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)
9089 {
9090         tridecal_t *decal;
9091         tridecal_t *decals;
9092         int i;
9093
9094         // expand or initialize the system
9095         if (decalsystem->maxdecals <= decalsystem->numdecals)
9096         {
9097                 decalsystem_t old = *decalsystem;
9098                 qbool useshortelements;
9099                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9100                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9101                 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)));
9102                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9103                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9104                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9105                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9106                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9107                 if (decalsystem->numdecals)
9108                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9109                 if (old.decals)
9110                         Mem_Free(old.decals);
9111                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9112                         decalsystem->element3i[i] = i;
9113                 if (useshortelements)
9114                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9115                                 decalsystem->element3s[i] = i;
9116         }
9117
9118         // grab a decal and search for another free slot for the next one
9119         decals = decalsystem->decals;
9120         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9121         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9122                 ;
9123         decalsystem->freedecal = i;
9124         if (decalsystem->numdecals <= i)
9125                 decalsystem->numdecals = i + 1;
9126
9127         // initialize the decal
9128         decal->lived = 0;
9129         decal->triangleindex = triangleindex;
9130         decal->surfaceindex = surfaceindex;
9131         decal->decalsequence = decalsequence;
9132         decal->color4f[0][0] = c0[0];
9133         decal->color4f[0][1] = c0[1];
9134         decal->color4f[0][2] = c0[2];
9135         decal->color4f[0][3] = 1;
9136         decal->color4f[1][0] = c1[0];
9137         decal->color4f[1][1] = c1[1];
9138         decal->color4f[1][2] = c1[2];
9139         decal->color4f[1][3] = 1;
9140         decal->color4f[2][0] = c2[0];
9141         decal->color4f[2][1] = c2[1];
9142         decal->color4f[2][2] = c2[2];
9143         decal->color4f[2][3] = 1;
9144         decal->vertex3f[0][0] = v0[0];
9145         decal->vertex3f[0][1] = v0[1];
9146         decal->vertex3f[0][2] = v0[2];
9147         decal->vertex3f[1][0] = v1[0];
9148         decal->vertex3f[1][1] = v1[1];
9149         decal->vertex3f[1][2] = v1[2];
9150         decal->vertex3f[2][0] = v2[0];
9151         decal->vertex3f[2][1] = v2[1];
9152         decal->vertex3f[2][2] = v2[2];
9153         decal->texcoord2f[0][0] = t0[0];
9154         decal->texcoord2f[0][1] = t0[1];
9155         decal->texcoord2f[1][0] = t1[0];
9156         decal->texcoord2f[1][1] = t1[1];
9157         decal->texcoord2f[2][0] = t2[0];
9158         decal->texcoord2f[2][1] = t2[1];
9159         TriangleNormal(v0, v1, v2, decal->plane);
9160         VectorNormalize(decal->plane);
9161         decal->plane[3] = DotProduct(v0, decal->plane);
9162 }
9163
9164 extern cvar_t cl_decals_bias;
9165 extern cvar_t cl_decals_models;
9166 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9167 // baseparms, parms, temps
9168 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)
9169 {
9170         int cornerindex;
9171         int index;
9172         float v[9][3];
9173         const float *vertex3f;
9174         const float *normal3f;
9175         int numpoints;
9176         float points[2][9][3];
9177         float temp[3];
9178         float tc[9][2];
9179         float f;
9180         float c[9][4];
9181         const int *e;
9182
9183         e = rsurface.modelelement3i + 3*triangleindex;
9184
9185         vertex3f = rsurface.modelvertex3f;
9186         normal3f = rsurface.modelnormal3f;
9187
9188         if (normal3f)
9189         {
9190                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9191                 {
9192                         index = 3*e[cornerindex];
9193                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9194                 }
9195         }
9196         else
9197         {
9198                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9199                 {
9200                         index = 3*e[cornerindex];
9201                         VectorCopy(vertex3f + index, v[cornerindex]);
9202                 }
9203         }
9204
9205         // cull backfaces
9206         //TriangleNormal(v[0], v[1], v[2], normal);
9207         //if (DotProduct(normal, localnormal) < 0.0f)
9208         //      continue;
9209         // clip by each of the box planes formed from the projection matrix
9210         // if anything survives, we emit the decal
9211         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]);
9212         if (numpoints < 3)
9213                 return;
9214         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]);
9215         if (numpoints < 3)
9216                 return;
9217         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]);
9218         if (numpoints < 3)
9219                 return;
9220         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]);
9221         if (numpoints < 3)
9222                 return;
9223         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]);
9224         if (numpoints < 3)
9225                 return;
9226         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]);
9227         if (numpoints < 3)
9228                 return;
9229         // some part of the triangle survived, so we have to accept it...
9230         if (dynamic)
9231         {
9232                 // dynamic always uses the original triangle
9233                 numpoints = 3;
9234                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9235                 {
9236                         index = 3*e[cornerindex];
9237                         VectorCopy(vertex3f + index, v[cornerindex]);
9238                 }
9239         }
9240         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9241         {
9242                 // convert vertex positions to texcoords
9243                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9244                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9245                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9246                 // calculate distance fade from the projection origin
9247                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9248                 f = bound(0.0f, f, 1.0f);
9249                 c[cornerindex][0] = r * f;
9250                 c[cornerindex][1] = g * f;
9251                 c[cornerindex][2] = b * f;
9252                 c[cornerindex][3] = 1.0f;
9253                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9254         }
9255         if (dynamic)
9256                 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);
9257         else
9258                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9259                         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);
9260 }
9261 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)
9262 {
9263         matrix4x4_t projection;
9264         decalsystem_t *decalsystem;
9265         qbool dynamic;
9266         model_t *model;
9267         const msurface_t *surface;
9268         const msurface_t *surfaces;
9269         const texture_t *texture;
9270         int numtriangles;
9271         int surfaceindex;
9272         int triangleindex;
9273         float localorigin[3];
9274         float localnormal[3];
9275         float localmins[3];
9276         float localmaxs[3];
9277         float localsize;
9278         //float normal[3];
9279         float planes[6][4];
9280         float angles[3];
9281         bih_t *bih;
9282         int bih_triangles_count;
9283         int bih_triangles[256];
9284         int bih_surfaces[256];
9285
9286         decalsystem = &ent->decalsystem;
9287         model = ent->model;
9288         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9289         {
9290                 R_DecalSystem_Reset(&ent->decalsystem);
9291                 return;
9292         }
9293
9294         if (!model->brush.data_leafs && !cl_decals_models.integer)
9295         {
9296                 if (decalsystem->model)
9297                         R_DecalSystem_Reset(decalsystem);
9298                 return;
9299         }
9300
9301         if (decalsystem->model != model)
9302                 R_DecalSystem_Reset(decalsystem);
9303         decalsystem->model = model;
9304
9305         RSurf_ActiveModelEntity(ent, true, false, false);
9306
9307         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9308         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9309         VectorNormalize(localnormal);
9310         localsize = worldsize*rsurface.inversematrixscale;
9311         localmins[0] = localorigin[0] - localsize;
9312         localmins[1] = localorigin[1] - localsize;
9313         localmins[2] = localorigin[2] - localsize;
9314         localmaxs[0] = localorigin[0] + localsize;
9315         localmaxs[1] = localorigin[1] + localsize;
9316         localmaxs[2] = localorigin[2] + localsize;
9317
9318         //VectorCopy(localnormal, planes[4]);
9319         //VectorVectors(planes[4], planes[2], planes[0]);
9320         AnglesFromVectors(angles, localnormal, NULL, false);
9321         AngleVectors(angles, planes[0], planes[2], planes[4]);
9322         VectorNegate(planes[0], planes[1]);
9323         VectorNegate(planes[2], planes[3]);
9324         VectorNegate(planes[4], planes[5]);
9325         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9326         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9327         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9328         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9329         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9330         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9331
9332 #if 1
9333 // works
9334 {
9335         matrix4x4_t forwardprojection;
9336         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9337         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9338 }
9339 #else
9340 // broken
9341 {
9342         float projectionvector[4][3];
9343         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9344         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9345         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9346         projectionvector[0][0] = planes[0][0] * ilocalsize;
9347         projectionvector[0][1] = planes[1][0] * ilocalsize;
9348         projectionvector[0][2] = planes[2][0] * ilocalsize;
9349         projectionvector[1][0] = planes[0][1] * ilocalsize;
9350         projectionvector[1][1] = planes[1][1] * ilocalsize;
9351         projectionvector[1][2] = planes[2][1] * ilocalsize;
9352         projectionvector[2][0] = planes[0][2] * ilocalsize;
9353         projectionvector[2][1] = planes[1][2] * ilocalsize;
9354         projectionvector[2][2] = planes[2][2] * ilocalsize;
9355         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9356         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9357         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9358         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9359 }
9360 #endif
9361
9362         dynamic = model->surfmesh.isanimated;
9363         surfaces = model->data_surfaces;
9364
9365         bih = NULL;
9366         bih_triangles_count = -1;
9367         if(!dynamic)
9368         {
9369                 if(model->render_bih.numleafs)
9370                         bih = &model->render_bih;
9371                 else if(model->collision_bih.numleafs)
9372                         bih = &model->collision_bih;
9373         }
9374         if(bih)
9375                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9376         if(bih_triangles_count == 0)
9377                 return;
9378         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9379                 return;
9380         if(bih_triangles_count > 0)
9381         {
9382                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9383                 {
9384                         surfaceindex = bih_surfaces[triangleindex];
9385                         surface = surfaces + surfaceindex;
9386                         texture = surface->texture;
9387                         if (!texture)
9388                                 continue;
9389                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9390                                 continue;
9391                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9392                                 continue;
9393                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9394                 }
9395         }
9396         else
9397         {
9398                 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
9399                 {
9400                         surface = surfaces + surfaceindex;
9401                         // check cull box first because it rejects more than any other check
9402                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9403                                 continue;
9404                         // skip transparent surfaces
9405                         texture = surface->texture;
9406                         if (!texture)
9407                                 continue;
9408                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9409                                 continue;
9410                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9411                                 continue;
9412                         numtriangles = surface->num_triangles;
9413                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9414                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9415                 }
9416         }
9417 }
9418
9419 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9420 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)
9421 {
9422         int renderentityindex;
9423         float worldmins[3];
9424         float worldmaxs[3];
9425         entity_render_t *ent;
9426
9427         worldmins[0] = worldorigin[0] - worldsize;
9428         worldmins[1] = worldorigin[1] - worldsize;
9429         worldmins[2] = worldorigin[2] - worldsize;
9430         worldmaxs[0] = worldorigin[0] + worldsize;
9431         worldmaxs[1] = worldorigin[1] + worldsize;
9432         worldmaxs[2] = worldorigin[2] + worldsize;
9433
9434         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9435
9436         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9437         {
9438                 ent = r_refdef.scene.entities[renderentityindex];
9439                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9440                         continue;
9441
9442                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9443         }
9444 }
9445
9446 typedef struct r_decalsystem_splatqueue_s
9447 {
9448         vec3_t worldorigin;
9449         vec3_t worldnormal;
9450         float color[4];
9451         float tcrange[4];
9452         float worldsize;
9453         unsigned int decalsequence;
9454 }
9455 r_decalsystem_splatqueue_t;
9456
9457 int r_decalsystem_numqueued = 0;
9458 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9459
9460 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)
9461 {
9462         r_decalsystem_splatqueue_t *queue;
9463
9464         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9465                 return;
9466
9467         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9468         VectorCopy(worldorigin, queue->worldorigin);
9469         VectorCopy(worldnormal, queue->worldnormal);
9470         Vector4Set(queue->color, r, g, b, a);
9471         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9472         queue->worldsize = worldsize;
9473         queue->decalsequence = cl.decalsequence++;
9474 }
9475
9476 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9477 {
9478         int i;
9479         r_decalsystem_splatqueue_t *queue;
9480
9481         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9482                 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);
9483         r_decalsystem_numqueued = 0;
9484 }
9485
9486 extern cvar_t cl_decals_max;
9487 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9488 {
9489         int i;
9490         decalsystem_t *decalsystem = &ent->decalsystem;
9491         int numdecals;
9492         unsigned int killsequence;
9493         tridecal_t *decal;
9494         float frametime;
9495         float lifetime;
9496
9497         if (!decalsystem->numdecals)
9498                 return;
9499
9500         if (r_showsurfaces.integer)
9501                 return;
9502
9503         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9504         {
9505                 R_DecalSystem_Reset(decalsystem);
9506                 return;
9507         }
9508
9509         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9510         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9511
9512         if (decalsystem->lastupdatetime)
9513                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9514         else
9515                 frametime = 0;
9516         decalsystem->lastupdatetime = r_refdef.scene.time;
9517         numdecals = decalsystem->numdecals;
9518
9519         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9520         {
9521                 if (decal->color4f[0][3])
9522                 {
9523                         decal->lived += frametime;
9524                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9525                         {
9526                                 memset(decal, 0, sizeof(*decal));
9527                                 if (decalsystem->freedecal > i)
9528                                         decalsystem->freedecal = i;
9529                         }
9530                 }
9531         }
9532         decal = decalsystem->decals;
9533         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9534                 numdecals--;
9535
9536         // collapse the array by shuffling the tail decals into the gaps
9537         for (;;)
9538         {
9539                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9540                         decalsystem->freedecal++;
9541                 if (decalsystem->freedecal == numdecals)
9542                         break;
9543                 decal[decalsystem->freedecal] = decal[--numdecals];
9544         }
9545
9546         decalsystem->numdecals = numdecals;
9547
9548         if (numdecals <= 0)
9549         {
9550                 // if there are no decals left, reset decalsystem
9551                 R_DecalSystem_Reset(decalsystem);
9552         }
9553 }
9554
9555 extern skinframe_t *decalskinframe;
9556 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9557 {
9558         int i;
9559         decalsystem_t *decalsystem = &ent->decalsystem;
9560         int numdecals;
9561         tridecal_t *decal;
9562         float faderate;
9563         float alpha;
9564         float *v3f;
9565         float *c4f;
9566         float *t2f;
9567         const int *e;
9568         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9569         int numtris = 0;
9570
9571         numdecals = decalsystem->numdecals;
9572         if (!numdecals)
9573                 return;
9574
9575         if (r_showsurfaces.integer)
9576                 return;
9577
9578         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9579         {
9580                 R_DecalSystem_Reset(decalsystem);
9581                 return;
9582         }
9583
9584         // if the model is static it doesn't matter what value we give for
9585         // wantnormals and wanttangents, so this logic uses only rules applicable
9586         // to a model, knowing that they are meaningless otherwise
9587         RSurf_ActiveModelEntity(ent, false, false, false);
9588
9589         decalsystem->lastupdatetime = r_refdef.scene.time;
9590
9591         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9592
9593         // update vertex positions for animated models
9594         v3f = decalsystem->vertex3f;
9595         c4f = decalsystem->color4f;
9596         t2f = decalsystem->texcoord2f;
9597         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9598         {
9599                 if (!decal->color4f[0][3])
9600                         continue;
9601
9602                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9603                         continue;
9604
9605                 // skip backfaces
9606                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9607                         continue;
9608
9609                 // update color values for fading decals
9610                 if (decal->lived >= cl_decals_time.value)
9611                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9612                 else
9613                         alpha = 1.0f;
9614
9615                 c4f[ 0] = decal->color4f[0][0] * alpha;
9616                 c4f[ 1] = decal->color4f[0][1] * alpha;
9617                 c4f[ 2] = decal->color4f[0][2] * alpha;
9618                 c4f[ 3] = 1;
9619                 c4f[ 4] = decal->color4f[1][0] * alpha;
9620                 c4f[ 5] = decal->color4f[1][1] * alpha;
9621                 c4f[ 6] = decal->color4f[1][2] * alpha;
9622                 c4f[ 7] = 1;
9623                 c4f[ 8] = decal->color4f[2][0] * alpha;
9624                 c4f[ 9] = decal->color4f[2][1] * alpha;
9625                 c4f[10] = decal->color4f[2][2] * alpha;
9626                 c4f[11] = 1;
9627
9628                 t2f[0] = decal->texcoord2f[0][0];
9629                 t2f[1] = decal->texcoord2f[0][1];
9630                 t2f[2] = decal->texcoord2f[1][0];
9631                 t2f[3] = decal->texcoord2f[1][1];
9632                 t2f[4] = decal->texcoord2f[2][0];
9633                 t2f[5] = decal->texcoord2f[2][1];
9634
9635                 // update vertex positions for animated models
9636                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9637                 {
9638                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9639                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9640                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9641                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9642                 }
9643                 else
9644                 {
9645                         VectorCopy(decal->vertex3f[0], v3f);
9646                         VectorCopy(decal->vertex3f[1], v3f + 3);
9647                         VectorCopy(decal->vertex3f[2], v3f + 6);
9648                 }
9649
9650                 if (r_refdef.fogenabled)
9651                 {
9652                         alpha = RSurf_FogVertex(v3f);
9653                         VectorScale(c4f, alpha, c4f);
9654                         alpha = RSurf_FogVertex(v3f + 3);
9655                         VectorScale(c4f + 4, alpha, c4f + 4);
9656                         alpha = RSurf_FogVertex(v3f + 6);
9657                         VectorScale(c4f + 8, alpha, c4f + 8);
9658                 }
9659
9660                 v3f += 9;
9661                 c4f += 12;
9662                 t2f += 6;
9663                 numtris++;
9664         }
9665
9666         if (numtris > 0)
9667         {
9668                 r_refdef.stats[r_stat_drawndecals] += numtris;
9669
9670                 // now render the decals all at once
9671                 // (this assumes they all use one particle font texture!)
9672                 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);
9673 //              R_Mesh_ResetTextureState();
9674                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9675                 GL_DepthMask(false);
9676                 GL_DepthRange(0, 1);
9677                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9678                 GL_DepthTest(true);
9679                 GL_CullFace(GL_NONE);
9680                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9681                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9682                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9683         }
9684 }
9685
9686 static void R_DrawModelDecals(void)
9687 {
9688         int i, numdecals;
9689
9690         // fade faster when there are too many decals
9691         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9692         for (i = 0;i < r_refdef.scene.numentities;i++)
9693                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9694
9695         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9696         for (i = 0;i < r_refdef.scene.numentities;i++)
9697                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9698                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9699
9700         R_DecalSystem_ApplySplatEntitiesQueue();
9701
9702         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9703         for (i = 0;i < r_refdef.scene.numentities;i++)
9704                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9705
9706         r_refdef.stats[r_stat_totaldecals] += numdecals;
9707
9708         if (r_showsurfaces.integer || !r_drawdecals.integer)
9709                 return;
9710
9711         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9712
9713         for (i = 0;i < r_refdef.scene.numentities;i++)
9714         {
9715                 if (!r_refdef.viewcache.entityvisible[i])
9716                         continue;
9717                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9718                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9719         }
9720 }
9721
9722 static void R_DrawDebugModel(void)
9723 {
9724         entity_render_t *ent = rsurface.entity;
9725         int j, flagsmask;
9726         const msurface_t *surface;
9727         model_t *model = ent->model;
9728
9729         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9730                 return;
9731
9732         if (r_showoverdraw.value > 0)
9733         {
9734                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9735                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9736                 R_SetupShader_Generic_NoTexture(false, false);
9737                 GL_DepthTest(false);
9738                 GL_DepthMask(false);
9739                 GL_DepthRange(0, 1);
9740                 GL_BlendFunc(GL_ONE, GL_ONE);
9741                 for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
9742                 {
9743                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9744                                 continue;
9745                         surface = model->data_surfaces + j;
9746                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9747                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9748                         {
9749                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9750                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9751                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9752                                         GL_Color(c, 0, 0, 1.0f);
9753                                 else if (ent == r_refdef.scene.worldentity)
9754                                         GL_Color(c, c, c, 1.0f);
9755                                 else
9756                                         GL_Color(0, c, 0, 1.0f);
9757                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9758                                 RSurf_DrawBatch();
9759                         }
9760                 }
9761                 rsurface.texture = NULL;
9762         }
9763
9764         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9765
9766 //      R_Mesh_ResetTextureState();
9767         R_SetupShader_Generic_NoTexture(false, false);
9768         GL_DepthRange(0, 1);
9769         GL_DepthTest(!r_showdisabledepthtest.integer);
9770         GL_DepthMask(false);
9771         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9772
9773         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9774         {
9775                 int triangleindex;
9776                 int bihleafindex;
9777                 qbool cullbox = false;
9778                 const q3mbrush_t *brush;
9779                 const bih_t *bih = &model->collision_bih;
9780                 const bih_leaf_t *bihleaf;
9781                 float vertex3f[3][3];
9782                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9783                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9784                 {
9785                         if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs))
9786                                 continue;
9787                         switch (bihleaf->type)
9788                         {
9789                         case BIH_BRUSH:
9790                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9791                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9792                                 {
9793                                         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);
9794                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9795                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9796                                 }
9797                                 break;
9798                         case BIH_COLLISIONTRIANGLE:
9799                                 triangleindex = bihleaf->itemindex;
9800                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9801                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9802                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9803                                 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);
9804                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9805                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9806                                 break;
9807                         case BIH_RENDERTRIANGLE:
9808                                 triangleindex = bihleaf->itemindex;
9809                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9810                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9811                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9812                                 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);
9813                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9814                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9815                                 break;
9816                         }
9817                 }
9818         }
9819
9820         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9821
9822 #ifndef USE_GLES2
9823         if (r_showtris.value > 0 && qglPolygonMode)
9824         {
9825                 if (r_showdisabledepthtest.integer)
9826                 {
9827                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9828                         GL_DepthMask(false);
9829                 }
9830                 else
9831                 {
9832                         GL_BlendFunc(GL_ONE, GL_ZERO);
9833                         GL_DepthMask(true);
9834                 }
9835                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9836                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9837                 {
9838                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9839                                 continue;
9840                         surface = model->data_surfaces + j;
9841                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9842                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9843                         {
9844                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9845                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9846                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9847                                 else if (ent == r_refdef.scene.worldentity)
9848                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9849                                 else
9850                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9851                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9852                                 RSurf_DrawBatch();
9853                         }
9854                 }
9855                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9856                 rsurface.texture = NULL;
9857         }
9858
9859 # if 0
9860         // FIXME!  implement r_shownormals with just triangles
9861         if (r_shownormals.value != 0 && qglBegin)
9862         {
9863                 int l, k;
9864                 vec3_t v;
9865                 if (r_showdisabledepthtest.integer)
9866                 {
9867                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9868                         GL_DepthMask(false);
9869                 }
9870                 else
9871                 {
9872                         GL_BlendFunc(GL_ONE, GL_ZERO);
9873                         GL_DepthMask(true);
9874                 }
9875                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9876                 {
9877                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9878                                 continue;
9879                         surface = model->data_surfaces + j;
9880                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9881                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9882                         {
9883                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9884                                 qglBegin(GL_LINES);
9885                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9886                                 {
9887                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9888                                         {
9889                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9890                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9891                                                 qglVertex3f(v[0], v[1], v[2]);
9892                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9893                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9894                                                 qglVertex3f(v[0], v[1], v[2]);
9895                                         }
9896                                 }
9897                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9898                                 {
9899                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9900                                         {
9901                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9902                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9903                                                 qglVertex3f(v[0], v[1], v[2]);
9904                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9905                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9906                                                 qglVertex3f(v[0], v[1], v[2]);
9907                                         }
9908                                 }
9909                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9910                                 {
9911                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9912                                         {
9913                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9914                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9915                                                 qglVertex3f(v[0], v[1], v[2]);
9916                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9917                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9918                                                 qglVertex3f(v[0], v[1], v[2]);
9919                                         }
9920                                 }
9921                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9922                                 {
9923                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9924                                         {
9925                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9926                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9927                                                 qglVertex3f(v[0], v[1], v[2]);
9928                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9929                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9930                                                 qglVertex3f(v[0], v[1], v[2]);
9931                                         }
9932                                 }
9933                                 qglEnd();
9934                                 CHECKGLERROR
9935                         }
9936                 }
9937                 rsurface.texture = NULL;
9938         }
9939 # endif
9940 #endif
9941 }
9942
9943 int r_maxsurfacelist = 0;
9944 const msurface_t **r_surfacelist = NULL;
9945 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
9946 {
9947         int i, j, flagsmask;
9948         model_t *model = ent->model;
9949         msurface_t *surfaces;
9950         unsigned char *update;
9951         int numsurfacelist = 0;
9952         if (model == NULL)
9953                 return;
9954
9955         if (r_maxsurfacelist < model->num_surfaces)
9956         {
9957                 r_maxsurfacelist = model->num_surfaces;
9958                 if (r_surfacelist)
9959                         Mem_Free((msurface_t **)r_surfacelist);
9960                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9961         }
9962
9963         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9964                 RSurf_ActiveModelEntity(ent, false, false, false);
9965         else if (prepass)
9966                 RSurf_ActiveModelEntity(ent, true, true, true);
9967         else if (depthonly)
9968                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9969         else
9970                 RSurf_ActiveModelEntity(ent, true, true, false);
9971
9972         surfaces = model->data_surfaces;
9973         update = model->brushq1.lightmapupdateflags;
9974
9975         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9976
9977         if (debug)
9978         {
9979                 R_DrawDebugModel();
9980                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9981                 return;
9982         }
9983
9984         // check if this is an empty model
9985         if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
9986                 return;
9987
9988         rsurface.lightmaptexture = NULL;
9989         rsurface.deluxemaptexture = NULL;
9990         rsurface.uselightmaptexture = false;
9991         rsurface.texture = NULL;
9992         rsurface.rtlight = NULL;
9993         numsurfacelist = 0;
9994
9995         // add visible surfaces to draw list
9996         if (ent == r_refdef.scene.worldentity)
9997         {
9998                 // for the world entity, check surfacevisible
9999                 for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
10000                 {
10001                         j = model->modelsurfaces_sorted[i];
10002                         if (r_refdef.viewcache.world_surfacevisible[j])
10003                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10004                 }
10005
10006                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10007                 if (!numsurfacelist)
10008                 {
10009                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10010                         return;
10011                 }
10012         }
10013         else if (ui)
10014         {
10015                 // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
10016                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10017                         r_surfacelist[numsurfacelist++] = surfaces + i;
10018         }
10019         else
10020         {
10021                 // add all surfaces
10022                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10023                         r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
10024         }
10025
10026         /*
10027          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10028          * using style chains because most styles do not change on most frames, and most
10029          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10030          * break this rule and animate most surfaces.
10031          */
10032         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10033         {
10034                 model_brush_lightstyleinfo_t *style;
10035
10036                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10037                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10038                 {
10039                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10040                         {
10041                                 int* list = style->surfacelist;
10042                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10043                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10044                                 for (j = 0; j < style->numsurfaces; j++)
10045                                         update[list[j]] = true;
10046                         }
10047                 }
10048                 // Now check if update flags are set on any surfaces that are visible
10049                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10050                 {
10051                         /* 
10052                          * We can do less frequent texture uploads (approximately 10hz for animated
10053                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10054                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10055                          * use model->num_surfaces, not nummodelsurfaces.
10056                          */
10057                         for (i = 0; i < model->num_surfaces;i++)
10058                                 if (update[i])
10059                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10060                 }
10061                 else
10062                 {
10063                         for (i = 0; i < numsurfacelist; i++)
10064                                 if (update[r_surfacelist[i] - surfaces])
10065                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10066                 }
10067         }
10068
10069         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10070
10071         // add to stats if desired
10072         if (r_speeds.integer && !skysurfaces && !depthonly)
10073         {
10074                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10075                 for (j = 0;j < numsurfacelist;j++)
10076                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10077         }
10078
10079         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10080 }
10081
10082 void R_DebugLine(vec3_t start, vec3_t end)
10083 {
10084         model_t *mod = CL_Mesh_UI();
10085         msurface_t *surf;
10086         int e0, e1, e2, e3;
10087         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10088         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10089         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10090         vec4_t w[2], s[2];
10091
10092         // transform to screen coords first
10093         Vector4Set(w[0], start[0], start[1], start[2], 1);
10094         Vector4Set(w[1], end[0], end[1], end[2], 1);
10095         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10096         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10097         x1 = s[0][0] * vid_conwidth.value / vid.width;
10098         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10099         x2 = s[1][0] * vid_conwidth.value / vid.width;
10100         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10101         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10102
10103         // add the line to the UI mesh for drawing later
10104
10105         // width is measured in real pixels
10106         if (fabs(x2 - x1) > fabs(y2 - y1))
10107         {
10108                 offsetx = 0;
10109                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10110         }
10111         else
10112         {
10113                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10114                 offsety = 0;
10115         }
10116         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);
10117         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10118         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10119         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10120         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10121         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10122         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10123
10124 }
10125
10126
10127 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)
10128 {
10129         static texture_t texture;
10130
10131         // fake enough texture and surface state to render this geometry
10132
10133         texture.update_lastrenderframe = -1; // regenerate this texture
10134         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10135         texture.basealpha = 1.0f;
10136         texture.currentskinframe = skinframe;
10137         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10138         texture.offsetmapping = OFFSETMAPPING_OFF;
10139         texture.offsetscale = 1;
10140         texture.specularscalemod = 1;
10141         texture.specularpowermod = 1;
10142         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10143
10144         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10145 }
10146
10147 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)
10148 {
10149         static msurface_t surface;
10150         const msurface_t *surfacelist = &surface;
10151
10152         // fake enough texture and surface state to render this geometry
10153         surface.texture = texture;
10154         surface.num_triangles = numtriangles;
10155         surface.num_firsttriangle = firsttriangle;
10156         surface.num_vertices = numvertices;
10157         surface.num_firstvertex = firstvertex;
10158
10159         // now render it
10160         rsurface.texture = R_GetCurrentTexture(surface.texture);
10161         rsurface.lightmaptexture = NULL;
10162         rsurface.deluxemaptexture = NULL;
10163         rsurface.uselightmaptexture = false;
10164         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10165 }