]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Don't lerp nailgun and super nailgun. Trades smoothness for better muzzle flash
[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 qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_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 = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_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 = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_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 = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_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 = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_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 = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_nolerp_list = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
210
211 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
213
214 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
216 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
217 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
220
221 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CVAR_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 = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
229 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
230 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
231
232 cvar_t r_smoothnormals_areaweighting = {CVAR_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 = {CVAR_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 = {CVAR_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 = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
239
240 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
241 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
244
245 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "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 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
249
250 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
251 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
252 {
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
256         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
257 };
258
259 extern cvar_t v_glslgamma_2d;
260
261 extern qboolean v_flipped_state;
262
263 r_framebufferstate_t r_fb;
264
265 /// shadow volume bsp struct with automatically growing nodes buffer
266 svbsp_t r_svbsp;
267
268 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
269
270 rtexture_t *r_texture_blanknormalmap;
271 rtexture_t *r_texture_white;
272 rtexture_t *r_texture_grey128;
273 rtexture_t *r_texture_black;
274 rtexture_t *r_texture_notexture;
275 rtexture_t *r_texture_whitecube;
276 rtexture_t *r_texture_normalizationcube;
277 rtexture_t *r_texture_fogattenuation;
278 rtexture_t *r_texture_fogheighttexture;
279 rtexture_t *r_texture_gammaramps;
280 unsigned int r_texture_gammaramps_serial;
281 //rtexture_t *r_texture_fogintensity;
282 rtexture_t *r_texture_reflectcube;
283
284 // TODO: hash lookups?
285 typedef struct cubemapinfo_s
286 {
287         char basename[64];
288         rtexture_t *texture;
289 }
290 cubemapinfo_t;
291
292 int r_texture_numcubemaps;
293 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
294
295 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
296 unsigned int r_numqueries;
297 unsigned int r_maxqueries;
298
299 typedef struct r_qwskincache_s
300 {
301         char name[MAX_QPATH];
302         skinframe_t *skinframe;
303 }
304 r_qwskincache_t;
305
306 static r_qwskincache_t *r_qwskincache;
307 static int r_qwskincache_size;
308
309 /// vertex coordinates for a quad that covers the screen exactly
310 extern const float r_screenvertex3f[12];
311 const float r_screenvertex3f[12] =
312 {
313         0, 0, 0,
314         1, 0, 0,
315         1, 1, 0,
316         0, 1, 0
317 };
318
319 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
320 {
321         int i;
322         for (i = 0;i < verts;i++)
323         {
324                 out[0] = in[0] * r;
325                 out[1] = in[1] * g;
326                 out[2] = in[2] * b;
327                 out[3] = in[3];
328                 in += 4;
329                 out += 4;
330         }
331 }
332
333 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
334 {
335         int i;
336         for (i = 0;i < verts;i++)
337         {
338                 out[0] = r;
339                 out[1] = g;
340                 out[2] = b;
341                 out[3] = a;
342                 out += 4;
343         }
344 }
345
346 // FIXME: move this to client?
347 void FOG_clear(void)
348 {
349         if (gamemode == GAME_NEHAHRA)
350         {
351                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
352                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
353                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
354                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
355                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
356         }
357         r_refdef.fog_density = 0;
358         r_refdef.fog_red = 0;
359         r_refdef.fog_green = 0;
360         r_refdef.fog_blue = 0;
361         r_refdef.fog_alpha = 1;
362         r_refdef.fog_start = 0;
363         r_refdef.fog_end = 16384;
364         r_refdef.fog_height = 1<<30;
365         r_refdef.fog_fadedepth = 128;
366         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
367 }
368
369 static void R_BuildBlankTextures(void)
370 {
371         unsigned char data[4];
372         data[2] = 128; // normal X
373         data[1] = 128; // normal Y
374         data[0] = 255; // normal Z
375         data[3] = 255; // height
376         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
377         data[0] = 255;
378         data[1] = 255;
379         data[2] = 255;
380         data[3] = 255;
381         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
382         data[0] = 128;
383         data[1] = 128;
384         data[2] = 128;
385         data[3] = 255;
386         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
387         data[0] = 0;
388         data[1] = 0;
389         data[2] = 0;
390         data[3] = 255;
391         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
392 }
393
394 static void R_BuildNoTexture(void)
395 {
396         int x, y;
397         unsigned char pix[16][16][4];
398         // this makes a light grey/dark grey checkerboard texture
399         for (y = 0;y < 16;y++)
400         {
401                 for (x = 0;x < 16;x++)
402                 {
403                         if ((y < 8) ^ (x < 8))
404                         {
405                                 pix[y][x][0] = 128;
406                                 pix[y][x][1] = 128;
407                                 pix[y][x][2] = 128;
408                                 pix[y][x][3] = 255;
409                         }
410                         else
411                         {
412                                 pix[y][x][0] = 64;
413                                 pix[y][x][1] = 64;
414                                 pix[y][x][2] = 64;
415                                 pix[y][x][3] = 255;
416                         }
417                 }
418         }
419         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
420 }
421
422 static void R_BuildWhiteCube(void)
423 {
424         unsigned char data[6*1*1*4];
425         memset(data, 255, sizeof(data));
426         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
427 }
428
429 static void R_BuildNormalizationCube(void)
430 {
431         int x, y, side;
432         vec3_t v;
433         vec_t s, t, intensity;
434 #define NORMSIZE 64
435         unsigned char *data;
436         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
437         for (side = 0;side < 6;side++)
438         {
439                 for (y = 0;y < NORMSIZE;y++)
440                 {
441                         for (x = 0;x < NORMSIZE;x++)
442                         {
443                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
445                                 switch(side)
446                                 {
447                                 default:
448                                 case 0:
449                                         v[0] = 1;
450                                         v[1] = -t;
451                                         v[2] = -s;
452                                         break;
453                                 case 1:
454                                         v[0] = -1;
455                                         v[1] = -t;
456                                         v[2] = s;
457                                         break;
458                                 case 2:
459                                         v[0] = s;
460                                         v[1] = 1;
461                                         v[2] = t;
462                                         break;
463                                 case 3:
464                                         v[0] = s;
465                                         v[1] = -1;
466                                         v[2] = -t;
467                                         break;
468                                 case 4:
469                                         v[0] = s;
470                                         v[1] = -t;
471                                         v[2] = 1;
472                                         break;
473                                 case 5:
474                                         v[0] = -s;
475                                         v[1] = -t;
476                                         v[2] = -1;
477                                         break;
478                                 }
479                                 intensity = 127.0f / sqrt(DotProduct(v, v));
480                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
481                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
482                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
483                                 data[((side*64+y)*64+x)*4+3] = 255;
484                         }
485                 }
486         }
487         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
488         Mem_Free(data);
489 }
490
491 static void R_BuildFogTexture(void)
492 {
493         int x, b;
494 #define FOGWIDTH 256
495         unsigned char data1[FOGWIDTH][4];
496         //unsigned char data2[FOGWIDTH][4];
497         double d, r, alpha;
498
499         r_refdef.fogmasktable_start = r_refdef.fog_start;
500         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
501         r_refdef.fogmasktable_range = r_refdef.fogrange;
502         r_refdef.fogmasktable_density = r_refdef.fog_density;
503
504         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
505         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
506         {
507                 d = (x * r - r_refdef.fogmasktable_start);
508                 if(developer_extra.integer)
509                         Con_DPrintf("%f ", d);
510                 d = max(0, d);
511                 if (r_fog_exp2.integer)
512                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
513                 else
514                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
515                 if(developer_extra.integer)
516                         Con_DPrintf(" : %f ", alpha);
517                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
518                 if(developer_extra.integer)
519                         Con_DPrintf(" = %f\n", alpha);
520                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
521         }
522
523         for (x = 0;x < FOGWIDTH;x++)
524         {
525                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
526                 data1[x][0] = b;
527                 data1[x][1] = b;
528                 data1[x][2] = b;
529                 data1[x][3] = 255;
530                 //data2[x][0] = 255 - b;
531                 //data2[x][1] = 255 - b;
532                 //data2[x][2] = 255 - b;
533                 //data2[x][3] = 255;
534         }
535         if (r_texture_fogattenuation)
536         {
537                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
539         }
540         else
541         {
542                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
543                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
544         }
545 }
546
547 static void R_BuildFogHeightTexture(void)
548 {
549         unsigned char *inpixels;
550         int size;
551         int x;
552         int y;
553         int j;
554         float c[4];
555         float f;
556         inpixels = NULL;
557         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
558         if (r_refdef.fogheighttexturename[0])
559                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
560         if (!inpixels)
561         {
562                 r_refdef.fog_height_tablesize = 0;
563                 if (r_texture_fogheighttexture)
564                         R_FreeTexture(r_texture_fogheighttexture);
565                 r_texture_fogheighttexture = NULL;
566                 if (r_refdef.fog_height_table2d)
567                         Mem_Free(r_refdef.fog_height_table2d);
568                 r_refdef.fog_height_table2d = NULL;
569                 if (r_refdef.fog_height_table1d)
570                         Mem_Free(r_refdef.fog_height_table1d);
571                 r_refdef.fog_height_table1d = NULL;
572                 return;
573         }
574         size = image_width;
575         r_refdef.fog_height_tablesize = size;
576         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
577         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
578         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
579         Mem_Free(inpixels);
580         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
581         // average fog color table accounting for every fog layer between a point
582         // and the camera.  (Note: attenuation is handled separately!)
583         for (y = 0;y < size;y++)
584         {
585                 for (x = 0;x < size;x++)
586                 {
587                         Vector4Clear(c);
588                         f = 0;
589                         if (x < y)
590                         {
591                                 for (j = x;j <= y;j++)
592                                 {
593                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
594                                         f++;
595                                 }
596                         }
597                         else
598                         {
599                                 for (j = x;j >= y;j--)
600                                 {
601                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
602                                         f++;
603                                 }
604                         }
605                         f = 1.0f / f;
606                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
609                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
610                 }
611         }
612         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
613 }
614
615 //=======================================================================================================================================================
616
617 static const char *builtinshaderstrings[] =
618 {
619 #include "shader_glsl.h"
620 0
621 };
622
623 //=======================================================================================================================================================
624
625 typedef struct shaderpermutationinfo_s
626 {
627         const char *pretext;
628         const char *name;
629 }
630 shaderpermutationinfo_t;
631
632 typedef struct shadermodeinfo_s
633 {
634         const char *sourcebasename;
635         const char *extension;
636         const char **builtinshaderstrings;
637         const char *pretext;
638         const char *name;
639         char *filename;
640         char *builtinstring;
641         int builtincrc;
642 }
643 shadermodeinfo_t;
644
645 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
646 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
647 {
648         {"#define USEDIFFUSE\n", " diffuse"},
649         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
650         {"#define USEVIEWTINT\n", " viewtint"},
651         {"#define USECOLORMAPPING\n", " colormapping"},
652         {"#define USESATURATION\n", " saturation"},
653         {"#define USEFOGINSIDE\n", " foginside"},
654         {"#define USEFOGOUTSIDE\n", " fogoutside"},
655         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
656         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
657         {"#define USEGAMMARAMPS\n", " gammaramps"},
658         {"#define USECUBEFILTER\n", " cubefilter"},
659         {"#define USEGLOW\n", " glow"},
660         {"#define USEBLOOM\n", " bloom"},
661         {"#define USESPECULAR\n", " specular"},
662         {"#define USEPOSTPROCESSING\n", " postprocessing"},
663         {"#define USEREFLECTION\n", " reflection"},
664         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
665         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
666         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
667         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
668         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
669         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
670         {"#define USEALPHAKILL\n", " alphakill"},
671         {"#define USEREFLECTCUBE\n", " reflectcube"},
672         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
673         {"#define USEBOUNCEGRID\n", " bouncegrid"},
674         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
675         {"#define USETRIPPY\n", " trippy"},
676         {"#define USEDEPTHRGB\n", " depthrgb"},
677         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
678         {"#define USESKELETAL\n", " skeletal"},
679         {"#define USEOCCLUDE\n", " occlude"}
680 };
681
682 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
683 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
684 {
685         // SHADERLANGUAGE_GLSL
686         {
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
703                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
704         },
705 };
706
707 struct r_glsl_permutation_s;
708 typedef struct r_glsl_permutation_s
709 {
710         /// hash lookup data
711         struct r_glsl_permutation_s *hashnext;
712         unsigned int mode;
713         uint64_t permutation;
714
715         /// indicates if we have tried compiling this permutation already
716         qboolean compiled;
717         /// 0 if compilation failed
718         int program;
719         // texture units assigned to each detected uniform
720         int tex_Texture_First;
721         int tex_Texture_Second;
722         int tex_Texture_GammaRamps;
723         int tex_Texture_Normal;
724         int tex_Texture_Color;
725         int tex_Texture_Gloss;
726         int tex_Texture_Glow;
727         int tex_Texture_SecondaryNormal;
728         int tex_Texture_SecondaryColor;
729         int tex_Texture_SecondaryGloss;
730         int tex_Texture_SecondaryGlow;
731         int tex_Texture_Pants;
732         int tex_Texture_Shirt;
733         int tex_Texture_FogHeightTexture;
734         int tex_Texture_FogMask;
735         int tex_Texture_LightGrid;
736         int tex_Texture_Lightmap;
737         int tex_Texture_Deluxemap;
738         int tex_Texture_Attenuation;
739         int tex_Texture_Cube;
740         int tex_Texture_Refraction;
741         int tex_Texture_Reflection;
742         int tex_Texture_ShadowMap2D;
743         int tex_Texture_CubeProjection;
744         int tex_Texture_ScreenNormalMap;
745         int tex_Texture_ScreenDiffuse;
746         int tex_Texture_ScreenSpecular;
747         int tex_Texture_ReflectMask;
748         int tex_Texture_ReflectCube;
749         int tex_Texture_BounceGrid;
750         /// locations of detected uniforms in program object, or -1 if not found
751         int loc_Texture_First;
752         int loc_Texture_Second;
753         int loc_Texture_GammaRamps;
754         int loc_Texture_Normal;
755         int loc_Texture_Color;
756         int loc_Texture_Gloss;
757         int loc_Texture_Glow;
758         int loc_Texture_SecondaryNormal;
759         int loc_Texture_SecondaryColor;
760         int loc_Texture_SecondaryGloss;
761         int loc_Texture_SecondaryGlow;
762         int loc_Texture_Pants;
763         int loc_Texture_Shirt;
764         int loc_Texture_FogHeightTexture;
765         int loc_Texture_FogMask;
766         int loc_Texture_LightGrid;
767         int loc_Texture_Lightmap;
768         int loc_Texture_Deluxemap;
769         int loc_Texture_Attenuation;
770         int loc_Texture_Cube;
771         int loc_Texture_Refraction;
772         int loc_Texture_Reflection;
773         int loc_Texture_ShadowMap2D;
774         int loc_Texture_CubeProjection;
775         int loc_Texture_ScreenNormalMap;
776         int loc_Texture_ScreenDiffuse;
777         int loc_Texture_ScreenSpecular;
778         int loc_Texture_ReflectMask;
779         int loc_Texture_ReflectCube;
780         int loc_Texture_BounceGrid;
781         int loc_Alpha;
782         int loc_BloomBlur_Parameters;
783         int loc_ClientTime;
784         int loc_Color_Ambient;
785         int loc_Color_Diffuse;
786         int loc_Color_Specular;
787         int loc_Color_Glow;
788         int loc_Color_Pants;
789         int loc_Color_Shirt;
790         int loc_DeferredColor_Ambient;
791         int loc_DeferredColor_Diffuse;
792         int loc_DeferredColor_Specular;
793         int loc_DeferredMod_Diffuse;
794         int loc_DeferredMod_Specular;
795         int loc_DistortScaleRefractReflect;
796         int loc_EyePosition;
797         int loc_FogColor;
798         int loc_FogHeightFade;
799         int loc_FogPlane;
800         int loc_FogPlaneViewDist;
801         int loc_FogRangeRecip;
802         int loc_LightColor;
803         int loc_LightDir;
804         int loc_LightGridMatrix;
805         int loc_LightGridNormalMatrix;
806         int loc_LightPosition;
807         int loc_OffsetMapping_ScaleSteps;
808         int loc_OffsetMapping_LodDistance;
809         int loc_OffsetMapping_Bias;
810         int loc_PixelSize;
811         int loc_ReflectColor;
812         int loc_ReflectFactor;
813         int loc_ReflectOffset;
814         int loc_RefractColor;
815         int loc_Saturation;
816         int loc_ScreenCenterRefractReflect;
817         int loc_ScreenScaleRefractReflect;
818         int loc_ScreenToDepth;
819         int loc_ShadowMap_Parameters;
820         int loc_ShadowMap_TextureScale;
821         int loc_SpecularPower;
822         int loc_Skeletal_Transform12;
823         int loc_UserVec1;
824         int loc_UserVec2;
825         int loc_UserVec3;
826         int loc_UserVec4;
827         int loc_ColorFringe;
828         int loc_ViewTintColor;
829         int loc_ViewToLight;
830         int loc_ModelToLight;
831         int loc_TexMatrix;
832         int loc_BackgroundTexMatrix;
833         int loc_ModelViewProjectionMatrix;
834         int loc_ModelViewMatrix;
835         int loc_PixelToScreenTexCoord;
836         int loc_ModelToReflectCube;
837         int loc_ShadowMapMatrix;
838         int loc_BloomColorSubtract;
839         int loc_NormalmapScrollBlend;
840         int loc_BounceGridMatrix;
841         int loc_BounceGridIntensity;
842         /// uniform block bindings
843         int ubibind_Skeletal_Transform12_UniformBlock;
844         /// uniform block indices
845         int ubiloc_Skeletal_Transform12_UniformBlock;
846 }
847 r_glsl_permutation_t;
848
849 #define SHADERPERMUTATION_HASHSIZE 256
850
851
852 // non-degradable "lightweight" shader parameters to keep the permutations simpler
853 // these can NOT degrade! only use for simple stuff
854 enum
855 {
856         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
857         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
858         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
859         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
860         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
861         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
862         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
863         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
864         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
865         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
866         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
867         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
868         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
869         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
870 };
871 #define SHADERSTATICPARMS_COUNT 14
872
873 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
874 static int shaderstaticparms_count = 0;
875
876 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
877 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
878
879 extern qboolean r_shadow_shadowmapsampler;
880 extern int r_shadow_shadowmappcf;
881 qboolean R_CompileShader_CheckStaticParms(void)
882 {
883         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
884         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
885         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
886
887         // detect all
888         if (r_glsl_saturation_redcompensate.integer)
889                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
890         if (r_glsl_vertextextureblend_usebothalphas.integer)
891                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
892         if (r_shadow_glossexact.integer)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
894         if (r_glsl_postprocess.integer)
895         {
896                 if (r_glsl_postprocess_uservec1_enable.integer)
897                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
898                 if (r_glsl_postprocess_uservec2_enable.integer)
899                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
900                 if (r_glsl_postprocess_uservec3_enable.integer)
901                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
902                 if (r_glsl_postprocess_uservec4_enable.integer)
903                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
904         }
905         if (r_fxaa.integer)
906                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
907         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
908                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
909
910         if (r_shadow_shadowmapsampler)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
912         if (r_shadow_shadowmappcf > 1)
913                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
914         else if (r_shadow_shadowmappcf)
915                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
916         if (r_celshading.integer)
917                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
918         if (r_celoutlines.integer)
919                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
920
921         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
922 }
923
924 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
925         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
926                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
927         else \
928                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
929 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
930 {
931         shaderstaticparms_count = 0;
932
933         // emit all
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
947         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
948 }
949
950 /// information about each possible shader permutation
951 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
952 /// currently selected permutation
953 r_glsl_permutation_t *r_glsl_permutation;
954 /// storage for permutations linked in the hash table
955 memexpandablearray_t r_glsl_permutationarray;
956
957 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
958 {
959         //unsigned int hashdepth = 0;
960         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
961         r_glsl_permutation_t *p;
962         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
963         {
964                 if (p->mode == mode && p->permutation == permutation)
965                 {
966                         //if (hashdepth > 10)
967                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
968                         return p;
969                 }
970                 //hashdepth++;
971         }
972         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
973         p->mode = mode;
974         p->permutation = permutation;
975         p->hashnext = r_glsl_permutationhash[mode][hashindex];
976         r_glsl_permutationhash[mode][hashindex] = p;
977         //if (hashdepth > 10)
978         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
979         return p;
980 }
981
982 static char *R_ShaderStrCat(const char **strings)
983 {
984         char *string, *s;
985         const char **p = strings;
986         const char *t;
987         size_t len = 0;
988         for (p = strings;(t = *p);p++)
989                 len += strlen(t);
990         len++;
991         s = string = (char *)Mem_Alloc(r_main_mempool, len);
992         len = 0;
993         for (p = strings;(t = *p);p++)
994         {
995                 len = strlen(t);
996                 memcpy(s, t, len);
997                 s += len;
998         }
999         *s = 0;
1000         return string;
1001 }
1002
1003 static char *R_ShaderStrCat(const char **strings);
1004 static void R_InitShaderModeInfo(void)
1005 {
1006         int i, language;
1007         shadermodeinfo_t *modeinfo;
1008         // 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)
1009         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1010         {
1011                 for (i = 0; i < SHADERMODE_COUNT; i++)
1012                 {
1013                         char filename[MAX_QPATH];
1014                         modeinfo = &shadermodeinfo[language][i];
1015                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1016                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1017                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1018                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1019                 }
1020         }
1021 }
1022
1023 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1024 {
1025         char *shaderstring;
1026         // if the mode has no filename we have to return the builtin string
1027         if (builtinonly || !modeinfo->filename)
1028                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1029         // note that FS_LoadFile appends a 0 byte to make it a valid string
1030         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1031         if (shaderstring)
1032         {
1033                 if (printfromdisknotice)
1034                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1035                 return shaderstring;
1036         }
1037         // fall back to builtinstring
1038         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1039 }
1040
1041 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1042 {
1043         int i;
1044         int ubibind;
1045         int sampler;
1046         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1047         char *sourcestring;
1048         char permutationname[256];
1049         int vertstrings_count = 0;
1050         int geomstrings_count = 0;
1051         int fragstrings_count = 0;
1052         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1053         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1054         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1055
1056         if (p->compiled)
1057                 return;
1058         p->compiled = true;
1059         p->program = 0;
1060
1061         permutationname[0] = 0;
1062         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1063
1064         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1065
1066         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1067         if(vid.support.glshaderversion >= 140)
1068         {
1069                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1070                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1071                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1072                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1073                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1074                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1075         }
1076         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1077         else if(vid.support.glshaderversion >= 130)
1078         {
1079                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1080                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1081                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1082                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1083                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1084                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1085         }
1086         // if we can do #version 120, we should (this adds the invariant keyword)
1087         else if(vid.support.glshaderversion >= 120)
1088         {
1089                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1090                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1091                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1092                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1093                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1094                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1095         }
1096         // GLES also adds several things from GLSL120
1097         switch(vid.renderpath)
1098         {
1099         case RENDERPATH_GLES2:
1100                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1101                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1102                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1103                 break;
1104         default:
1105                 break;
1106         }
1107
1108         // the first pretext is which type of shader to compile as
1109         // (later these will all be bound together as a program object)
1110         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1111         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1112         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1113
1114         // the second pretext is the mode (for example a light source)
1115         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1116         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1117         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1118         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1119
1120         // now add all the permutation pretexts
1121         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1122         {
1123                 if (permutation & (1ll<<i))
1124                 {
1125                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1126                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1127                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1128                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1129                 }
1130                 else
1131                 {
1132                         // keep line numbers correct
1133                         vertstrings_list[vertstrings_count++] = "\n";
1134                         geomstrings_list[geomstrings_count++] = "\n";
1135                         fragstrings_list[fragstrings_count++] = "\n";
1136                 }
1137         }
1138
1139         // add static parms
1140         R_CompileShader_AddStaticParms(mode, permutation);
1141         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1142         vertstrings_count += shaderstaticparms_count;
1143         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1144         geomstrings_count += shaderstaticparms_count;
1145         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1146         fragstrings_count += shaderstaticparms_count;
1147
1148         // now append the shader text itself
1149         vertstrings_list[vertstrings_count++] = sourcestring;
1150         geomstrings_list[geomstrings_count++] = sourcestring;
1151         fragstrings_list[fragstrings_count++] = sourcestring;
1152
1153         // we don't currently use geometry shaders for anything, so just empty the list
1154         geomstrings_count = 0;
1155
1156         // compile the shader program
1157         if (vertstrings_count + geomstrings_count + fragstrings_count)
1158                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1159         if (p->program)
1160         {
1161                 CHECKGLERROR
1162                 qglUseProgram(p->program);CHECKGLERROR
1163                 // look up all the uniform variable names we care about, so we don't
1164                 // have to look them up every time we set them
1165
1166 #if 0
1167                 // debugging aid
1168                 {
1169                         GLint activeuniformindex = 0;
1170                         GLint numactiveuniforms = 0;
1171                         char uniformname[128];
1172                         GLsizei uniformnamelength = 0;
1173                         GLint uniformsize = 0;
1174                         GLenum uniformtype = 0;
1175                         memset(uniformname, 0, sizeof(uniformname));
1176                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1177                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1178                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1179                         {
1180                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1181                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1182                         }
1183                 }
1184 #endif
1185
1186                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1187                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1188                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1189                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1190                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1191                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1192                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1193                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1194                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1195                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1196                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1197                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1198                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1199                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1200                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1201                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1202                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1203                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1204                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1205                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1206                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1207                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1208                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1209                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1210                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1211                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1212                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1213                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1214                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1215                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1216                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1217                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1218                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1219                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1220                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1221                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1222                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1223                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1224                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1225                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1226                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1227                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1228                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1229                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1230                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1231                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1232                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1233                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1234                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1235                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1236                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1237                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1238                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1239                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1240                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1241                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1242                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1243                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1244                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1245                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1246                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1247                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1248                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1249                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1250                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1251                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1252                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1253                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1254                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1255                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1256                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1257                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1258                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1259                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1260                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1261                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1262                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1263                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1264                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1265                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1266                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1267                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1268                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1269                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1270                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1271                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1272                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1273                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1274                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1275                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1276                 // initialize the samplers to refer to the texture units we use
1277                 p->tex_Texture_First = -1;
1278                 p->tex_Texture_Second = -1;
1279                 p->tex_Texture_GammaRamps = -1;
1280                 p->tex_Texture_Normal = -1;
1281                 p->tex_Texture_Color = -1;
1282                 p->tex_Texture_Gloss = -1;
1283                 p->tex_Texture_Glow = -1;
1284                 p->tex_Texture_SecondaryNormal = -1;
1285                 p->tex_Texture_SecondaryColor = -1;
1286                 p->tex_Texture_SecondaryGloss = -1;
1287                 p->tex_Texture_SecondaryGlow = -1;
1288                 p->tex_Texture_Pants = -1;
1289                 p->tex_Texture_Shirt = -1;
1290                 p->tex_Texture_FogHeightTexture = -1;
1291                 p->tex_Texture_FogMask = -1;
1292                 p->tex_Texture_LightGrid = -1;
1293                 p->tex_Texture_Lightmap = -1;
1294                 p->tex_Texture_Deluxemap = -1;
1295                 p->tex_Texture_Attenuation = -1;
1296                 p->tex_Texture_Cube = -1;
1297                 p->tex_Texture_Refraction = -1;
1298                 p->tex_Texture_Reflection = -1;
1299                 p->tex_Texture_ShadowMap2D = -1;
1300                 p->tex_Texture_CubeProjection = -1;
1301                 p->tex_Texture_ScreenNormalMap = -1;
1302                 p->tex_Texture_ScreenDiffuse = -1;
1303                 p->tex_Texture_ScreenSpecular = -1;
1304                 p->tex_Texture_ReflectMask = -1;
1305                 p->tex_Texture_ReflectCube = -1;
1306                 p->tex_Texture_BounceGrid = -1;
1307                 // bind the texture samplers in use
1308                 sampler = 0;
1309                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1310                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1311                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1312                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1313                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1314                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1315                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1316                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1317                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1318                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1319                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1320                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1321                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1322                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1323                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1324                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1325                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1326                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1327                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1328                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1329                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1330                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1331                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1332                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1333                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1334                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1335                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1336                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1337                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1338                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1339                 // get the uniform block indices so we can bind them
1340                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1341 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1342                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1343 #endif
1344                 // clear the uniform block bindings
1345                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1346                 // bind the uniform blocks in use
1347                 ubibind = 0;
1348 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1349                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1350 #endif
1351                 // we're done compiling and setting up the shader, at least until it is used
1352                 CHECKGLERROR
1353                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1354         }
1355         else
1356                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1357
1358         // free the strings
1359         if (sourcestring)
1360                 Mem_Free(sourcestring);
1361 }
1362
1363 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1364 {
1365         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1366         if (r_glsl_permutation != perm)
1367         {
1368                 r_glsl_permutation = perm;
1369                 if (!r_glsl_permutation->program)
1370                 {
1371                         if (!r_glsl_permutation->compiled)
1372                         {
1373                                 Con_DPrintf("Compiling shader mode %u permutation %"PRIx64"\n", mode, permutation);
1374                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1375                         }
1376                         if (!r_glsl_permutation->program)
1377                         {
1378                                 // remove features until we find a valid permutation
1379                                 int i;
1380                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1381                                 {
1382                                         // reduce i more quickly whenever it would not remove any bits
1383                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1384                                         if (!(permutation & j))
1385                                                 continue;
1386                                         permutation -= j;
1387                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1388                                         if (!r_glsl_permutation->compiled)
1389                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1390                                         if (r_glsl_permutation->program)
1391                                                 break;
1392                                 }
1393                                 if (i >= SHADERPERMUTATION_COUNT)
1394                                 {
1395                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1396                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1397                                         qglUseProgram(0);CHECKGLERROR
1398                                         return; // no bit left to clear, entire mode is broken
1399                                 }
1400                         }
1401                 }
1402                 CHECKGLERROR
1403                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1404         }
1405         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1406         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1407         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1408         CHECKGLERROR
1409 }
1410
1411 void R_GLSL_Restart_f(cmd_state_t *cmd)
1412 {
1413         unsigned int i, limit;
1414         switch(vid.renderpath)
1415         {
1416         case RENDERPATH_GL32:
1417         case RENDERPATH_GLES2:
1418                 {
1419                         r_glsl_permutation_t *p;
1420                         r_glsl_permutation = NULL;
1421                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1422                         for (i = 0;i < limit;i++)
1423                         {
1424                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1425                                 {
1426                                         GL_Backend_FreeProgram(p->program);
1427                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1428                                 }
1429                         }
1430                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1431                 }
1432                 break;
1433         }
1434 }
1435
1436 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1437 {
1438         int i, language, mode, dupe;
1439         char *text;
1440         shadermodeinfo_t *modeinfo;
1441         qfile_t *file;
1442
1443         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1444         {
1445                 modeinfo = shadermodeinfo[language];
1446                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1447                 {
1448                         // don't dump the same file multiple times (most or all shaders come from the same file)
1449                         for (dupe = mode - 1;dupe >= 0;dupe--)
1450                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1451                                         break;
1452                         if (dupe >= 0)
1453                                 continue;
1454                         text = modeinfo[mode].builtinstring;
1455                         if (!text)
1456                                 continue;
1457                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1458                         if (file)
1459                         {
1460                                 FS_Print(file, "/* The engine may define the following macros:\n");
1461                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1462                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1463                                         FS_Print(file, modeinfo[i].pretext);
1464                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1465                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1466                                 FS_Print(file, "*/\n");
1467                                 FS_Print(file, text);
1468                                 FS_Close(file);
1469                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1470                         }
1471                         else
1472                                 Con_Errorf("failed to write to %s\n", modeinfo[mode].filename);
1473                 }
1474         }
1475 }
1476
1477 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1478 {
1479         uint64_t permutation = 0;
1480         if (r_trippy.integer && !notrippy)
1481                 permutation |= SHADERPERMUTATION_TRIPPY;
1482         permutation |= SHADERPERMUTATION_VIEWTINT;
1483         if (t)
1484                 permutation |= SHADERPERMUTATION_DIFFUSE;
1485         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1486                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1487         if (suppresstexalpha)
1488                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1489         if (vid.allowalphatocoverage)
1490                 GL_AlphaToCoverage(false);
1491         switch (vid.renderpath)
1492         {
1493         case RENDERPATH_GL32:
1494         case RENDERPATH_GLES2:
1495                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1496                 if (r_glsl_permutation->tex_Texture_First >= 0)
1497                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1498                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1499                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1500                 break;
1501         }
1502 }
1503
1504 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1505 {
1506         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1507 }
1508
1509 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1510 {
1511         uint64_t permutation = 0;
1512         if (r_trippy.integer && !notrippy)
1513                 permutation |= SHADERPERMUTATION_TRIPPY;
1514         if (depthrgb)
1515                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1516         if (skeletal)
1517                 permutation |= SHADERPERMUTATION_SKELETAL;
1518
1519         if (vid.allowalphatocoverage)
1520                 GL_AlphaToCoverage(false);
1521         switch (vid.renderpath)
1522         {
1523         case RENDERPATH_GL32:
1524         case RENDERPATH_GLES2:
1525                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1526 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1527                 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);
1528 #endif
1529                 break;
1530         }
1531 }
1532
1533 #define BLENDFUNC_ALLOWS_COLORMOD      1
1534 #define BLENDFUNC_ALLOWS_FOG           2
1535 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1536 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1537 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1538 static int R_BlendFuncFlags(int src, int dst)
1539 {
1540         int r = 0;
1541
1542         // a blendfunc allows colormod if:
1543         // a) it can never keep the destination pixel invariant, or
1544         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1545         // this is to prevent unintended side effects from colormod
1546
1547         // a blendfunc allows fog if:
1548         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1549         // this is to prevent unintended side effects from fog
1550
1551         // these checks are the output of fogeval.pl
1552
1553         r |= BLENDFUNC_ALLOWS_COLORMOD;
1554         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1561         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1562         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1563         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1564         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1566         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1567         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1568         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1569         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1571         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1572         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1574         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1575
1576         return r;
1577 }
1578
1579 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1580 {
1581         // select a permutation of the lighting shader appropriate to this
1582         // combination of texture, entity, light source, and fogging, only use the
1583         // minimum features necessary to avoid wasting rendering time in the
1584         // fragment shader on features that are not being used
1585         uint64_t permutation = 0;
1586         unsigned int mode = 0;
1587         int blendfuncflags;
1588         texture_t *t = rsurface.texture;
1589         float m16f[16];
1590         matrix4x4_t tempmatrix;
1591         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1592         if (r_trippy.integer && !notrippy)
1593                 permutation |= SHADERPERMUTATION_TRIPPY;
1594         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1595                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1596         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1597                 permutation |= SHADERPERMUTATION_OCCLUDE;
1598         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1599                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1600         if (rsurfacepass == RSURFPASS_BACKGROUND)
1601         {
1602                 // distorted background
1603                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1604                 {
1605                         mode = SHADERMODE_WATER;
1606                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1607                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1608                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1609                         {
1610                                 // this is the right thing to do for wateralpha
1611                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1612                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1613                         }
1614                         else
1615                         {
1616                                 // this is the right thing to do for entity alpha
1617                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1619                         }
1620                 }
1621                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1622                 {
1623                         mode = SHADERMODE_REFRACTION;
1624                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1625                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1626                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1628                 }
1629                 else
1630                 {
1631                         mode = SHADERMODE_GENERIC;
1632                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1633                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1634                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1635                 }
1636                 if (vid.allowalphatocoverage)
1637                         GL_AlphaToCoverage(false);
1638         }
1639         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1640         {
1641                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1642                 {
1643                         switch(t->offsetmapping)
1644                         {
1645                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1646                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1647                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1648                         case OFFSETMAPPING_OFF: break;
1649                         }
1650                 }
1651                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1652                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1653                 // normalmap (deferred prepass), may use alpha test on diffuse
1654                 mode = SHADERMODE_DEFERREDGEOMETRY;
1655                 GL_BlendFunc(GL_ONE, GL_ZERO);
1656                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1657                 if (vid.allowalphatocoverage)
1658                         GL_AlphaToCoverage(false);
1659         }
1660         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1661         {
1662                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1663                 {
1664                         switch(t->offsetmapping)
1665                         {
1666                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1667                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1668                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1669                         case OFFSETMAPPING_OFF: break;
1670                         }
1671                 }
1672                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1673                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1674                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1675                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1676                 // light source
1677                 mode = SHADERMODE_LIGHTSOURCE;
1678                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1679                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1680                 if (VectorLength2(rtlightdiffuse) > 0)
1681                         permutation |= SHADERPERMUTATION_DIFFUSE;
1682                 if (VectorLength2(rtlightspecular) > 0)
1683                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1684                 if (r_refdef.fogenabled)
1685                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1686                 if (t->colormapping)
1687                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1688                 if (r_shadow_usingshadowmap2d)
1689                 {
1690                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1691                         if(r_shadow_shadowmapvsdct)
1692                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1693
1694                         if (r_shadow_shadowmap2ddepthbuffer)
1695                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1696                 }
1697                 if (t->reflectmasktexture)
1698                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1699                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1700                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1701                 if (vid.allowalphatocoverage)
1702                         GL_AlphaToCoverage(false);
1703         }
1704         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1705         {
1706                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1707                 {
1708                         switch(t->offsetmapping)
1709                         {
1710                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1711                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1712                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1713                         case OFFSETMAPPING_OFF: break;
1714                         }
1715                 }
1716                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1717                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1718                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1719                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1720                 // directional model lighting
1721                 mode = SHADERMODE_LIGHTGRID;
1722                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1723                         permutation |= SHADERPERMUTATION_GLOW;
1724                 permutation |= SHADERPERMUTATION_DIFFUSE;
1725                 if (t->glosstexture || t->backgroundglosstexture)
1726                         permutation |= SHADERPERMUTATION_SPECULAR;
1727                 if (r_refdef.fogenabled)
1728                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1729                 if (t->colormapping)
1730                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1731                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1732                 {
1733                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1734                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1735
1736                         if (r_shadow_shadowmap2ddepthbuffer)
1737                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1738                 }
1739                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1740                         permutation |= SHADERPERMUTATION_REFLECTION;
1741                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1742                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1743                 if (t->reflectmasktexture)
1744                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1745                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1746                 {
1747                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1748                         if (r_shadow_bouncegrid_state.directional)
1749                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1750                 }
1751                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1752                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1753                 // when using alphatocoverage, we don't need alphakill
1754                 if (vid.allowalphatocoverage)
1755                 {
1756                         if (r_transparent_alphatocoverage.integer)
1757                         {
1758                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1759                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1760                         }
1761                         else
1762                                 GL_AlphaToCoverage(false);
1763                 }
1764         }
1765         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1766         {
1767                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1768                 {
1769                         switch(t->offsetmapping)
1770                         {
1771                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1772                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1773                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1774                         case OFFSETMAPPING_OFF: break;
1775                         }
1776                 }
1777                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1778                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1779                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1780                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1781                 // directional model lighting
1782                 mode = SHADERMODE_LIGHTDIRECTION;
1783                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1784                         permutation |= SHADERPERMUTATION_GLOW;
1785                 if (VectorLength2(t->render_modellight_diffuse))
1786                         permutation |= SHADERPERMUTATION_DIFFUSE;
1787                 if (VectorLength2(t->render_modellight_specular) > 0)
1788                         permutation |= SHADERPERMUTATION_SPECULAR;
1789                 if (r_refdef.fogenabled)
1790                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1791                 if (t->colormapping)
1792                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1793                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1794                 {
1795                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1796                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1797
1798                         if (r_shadow_shadowmap2ddepthbuffer)
1799                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1800                 }
1801                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1802                         permutation |= SHADERPERMUTATION_REFLECTION;
1803                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1804                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1805                 if (t->reflectmasktexture)
1806                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1807                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1808                 {
1809                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1810                         if (r_shadow_bouncegrid_state.directional)
1811                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1812                 }
1813                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1814                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1815                 // when using alphatocoverage, we don't need alphakill
1816                 if (vid.allowalphatocoverage)
1817                 {
1818                         if (r_transparent_alphatocoverage.integer)
1819                         {
1820                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1821                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1822                         }
1823                         else
1824                                 GL_AlphaToCoverage(false);
1825                 }
1826         }
1827         else
1828         {
1829                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1830                 {
1831                         switch(t->offsetmapping)
1832                         {
1833                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1834                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1835                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1836                         case OFFSETMAPPING_OFF: break;
1837                         }
1838                 }
1839                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1840                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1841                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1842                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1843                 // lightmapped wall
1844                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1845                         permutation |= SHADERPERMUTATION_GLOW;
1846                 if (r_refdef.fogenabled)
1847                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1848                 if (t->colormapping)
1849                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1850                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1851                 {
1852                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1853                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1854
1855                         if (r_shadow_shadowmap2ddepthbuffer)
1856                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1857                 }
1858                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1859                         permutation |= SHADERPERMUTATION_REFLECTION;
1860                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1861                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1862                 if (t->reflectmasktexture)
1863                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1864                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1865                 {
1866                         // deluxemapping (light direction texture)
1867                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1868                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1869                         else
1870                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1871                         permutation |= SHADERPERMUTATION_DIFFUSE;
1872                         if (VectorLength2(t->render_lightmap_specular) > 0)
1873                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1874                 }
1875                 else if (r_glsl_deluxemapping.integer >= 2)
1876                 {
1877                         // fake deluxemapping (uniform light direction in tangentspace)
1878                         if (rsurface.uselightmaptexture)
1879                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1880                         else
1881                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1882                         permutation |= SHADERPERMUTATION_DIFFUSE;
1883                         if (VectorLength2(t->render_lightmap_specular) > 0)
1884                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1885                 }
1886                 else if (rsurface.uselightmaptexture)
1887                 {
1888                         // ordinary lightmapping (q1bsp, q3bsp)
1889                         mode = SHADERMODE_LIGHTMAP;
1890                 }
1891                 else
1892                 {
1893                         // ordinary vertex coloring (q3bsp)
1894                         mode = SHADERMODE_VERTEXCOLOR;
1895                 }
1896                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1897                 {
1898                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1899                         if (r_shadow_bouncegrid_state.directional)
1900                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1901                 }
1902                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1903                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1904                 // when using alphatocoverage, we don't need alphakill
1905                 if (vid.allowalphatocoverage)
1906                 {
1907                         if (r_transparent_alphatocoverage.integer)
1908                         {
1909                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1910                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1911                         }
1912                         else
1913                                 GL_AlphaToCoverage(false);
1914                 }
1915         }
1916         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1917                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1918         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !notrippy)
1919                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1920         switch(vid.renderpath)
1921         {
1922         case RENDERPATH_GL32:
1923         case RENDERPATH_GLES2:
1924                 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);
1925                 RSurf_UploadBuffersForBatch();
1926                 // this has to be after RSurf_PrepareVerticesForBatch
1927                 if (rsurface.batchskeletaltransform3x4buffer)
1928                         permutation |= SHADERPERMUTATION_SKELETAL;
1929                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1930 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1931                 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);
1932 #endif
1933                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1934                 if (mode == SHADERMODE_LIGHTSOURCE)
1935                 {
1936                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1937                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1938                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1939                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1940                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1941                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1942         
1943                         // additive passes are only darkened by fog, not tinted
1944                         if (r_glsl_permutation->loc_FogColor >= 0)
1945                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1946                         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);
1947                 }
1948                 else
1949                 {
1950                         if (mode == SHADERMODE_FLATCOLOR)
1951                         {
1952                                 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]);
1953                         }
1954                         else if (mode == SHADERMODE_LIGHTGRID)
1955                         {
1956                                 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]);
1957                                 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]);
1958                                 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]);
1959                                 // other LightGrid uniforms handled below
1960                         }
1961                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1962                         {
1963                                 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]);
1964                                 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]);
1965                                 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]);
1966                                 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]);
1967                                 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]);
1968                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1969                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1970                         }
1971                         else
1972                         {
1973                                 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]);
1974                                 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]);
1975                                 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]);
1976                                 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]);
1977                                 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]);
1978                         }
1979                         // additive passes are only darkened by fog, not tinted
1980                         if (r_glsl_permutation->loc_FogColor >= 0 && !notrippy)
1981                         {
1982                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1983                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1984                                 else
1985                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1986                         }
1987                         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);
1988                         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]);
1989                         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]);
1990                         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);
1991                         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);
1992                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1993                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1994                         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);
1995                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1996                 }
1997                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1998                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1999                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
2000                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
2001                 {
2002                         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]);
2003                         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]);
2004                 }
2005                 else
2006                 {
2007                         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]);
2008                         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]);
2009                 }
2010
2011                 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]);
2012                 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));
2013                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2014                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2015                 {
2016                         if (t->pantstexture)
2017                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2018                         else
2019                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2020                 }
2021                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2022                 {
2023                         if (t->shirttexture)
2024                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2025                         else
2026                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2027                 }
2028                 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]);
2029                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2030                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2031                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2032                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2033                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2034                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2035                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2036                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2037                         );
2038                 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);
2039                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2040                 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]);
2041                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2042                 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);}
2043                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2044                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2045                 {
2046                         float m9f[9];
2047                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2048                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2049                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2050                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2051                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2052                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2053                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2054                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2055                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2056                 }
2057
2058                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2059                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2060                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2061                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2062                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2063                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2064                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2065                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2066                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2067                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2068                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2069                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2070                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2071                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2072                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2073                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2074                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2075                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2076                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2077                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2078                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2079                 {
2080                         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);
2081                         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);
2082                         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);
2083                 }
2084                 else
2085                 {
2086                         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);
2087                 }
2088                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2089                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2090                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2091                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2092                 {
2093                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2094                         if (rsurface.rtlight)
2095                         {
2096                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2097                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2098                         }
2099                 }
2100                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2101                 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);
2102                 CHECKGLERROR
2103                 break;
2104         }
2105 }
2106
2107 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2108 {
2109         // select a permutation of the lighting shader appropriate to this
2110         // combination of texture, entity, light source, and fogging, only use the
2111         // minimum features necessary to avoid wasting rendering time in the
2112         // fragment shader on features that are not being used
2113         uint64_t permutation = 0;
2114         unsigned int mode = 0;
2115         const float *lightcolorbase = rtlight->currentcolor;
2116         float ambientscale = rtlight->ambientscale;
2117         float diffusescale = rtlight->diffusescale;
2118         float specularscale = rtlight->specularscale;
2119         // this is the location of the light in view space
2120         vec3_t viewlightorigin;
2121         // this transforms from view space (camera) to light space (cubemap)
2122         matrix4x4_t viewtolight;
2123         matrix4x4_t lighttoview;
2124         float viewtolight16f[16];
2125         // light source
2126         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2127         if (rtlight->currentcubemap != r_texture_whitecube)
2128                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2129         if (diffusescale > 0)
2130                 permutation |= SHADERPERMUTATION_DIFFUSE;
2131         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2132                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2133         if (r_shadow_usingshadowmap2d)
2134         {
2135                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2136                 if (r_shadow_shadowmapvsdct)
2137                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2138
2139                 if (r_shadow_shadowmap2ddepthbuffer)
2140                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2141         }
2142         if (vid.allowalphatocoverage)
2143                 GL_AlphaToCoverage(false);
2144         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2145         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2146         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2147         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2148         switch(vid.renderpath)
2149         {
2150         case RENDERPATH_GL32:
2151         case RENDERPATH_GLES2:
2152                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2153                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2154                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2155                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2156                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2157                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2158                 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]);
2159                 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]);
2160                 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);
2161                 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]);
2162                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2163
2164                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2165                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2166                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2167                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2168                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2169                 break;
2170         }
2171 }
2172
2173 #define SKINFRAME_HASH 1024
2174
2175 typedef struct
2176 {
2177         unsigned int loadsequence; // incremented each level change
2178         memexpandablearray_t array;
2179         skinframe_t *hash[SKINFRAME_HASH];
2180 }
2181 r_skinframe_t;
2182 r_skinframe_t r_skinframe;
2183
2184 void R_SkinFrame_PrepareForPurge(void)
2185 {
2186         r_skinframe.loadsequence++;
2187         // wrap it without hitting zero
2188         if (r_skinframe.loadsequence >= 200)
2189                 r_skinframe.loadsequence = 1;
2190 }
2191
2192 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2193 {
2194         if (!skinframe)
2195                 return;
2196         // mark the skinframe as used for the purging code
2197         skinframe->loadsequence = r_skinframe.loadsequence;
2198 }
2199
2200 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2201 {
2202         if (s == NULL)
2203                 return;
2204         if (s->merged == s->base)
2205                 s->merged = NULL;
2206         R_PurgeTexture(s->stain); s->stain = NULL;
2207         R_PurgeTexture(s->merged); s->merged = NULL;
2208         R_PurgeTexture(s->base); s->base = NULL;
2209         R_PurgeTexture(s->pants); s->pants = NULL;
2210         R_PurgeTexture(s->shirt); s->shirt = NULL;
2211         R_PurgeTexture(s->nmap); s->nmap = NULL;
2212         R_PurgeTexture(s->gloss); s->gloss = NULL;
2213         R_PurgeTexture(s->glow); s->glow = NULL;
2214         R_PurgeTexture(s->fog); s->fog = NULL;
2215         R_PurgeTexture(s->reflect); s->reflect = NULL;
2216         s->loadsequence = 0;
2217 }
2218
2219 void R_SkinFrame_Purge(void)
2220 {
2221         int i;
2222         skinframe_t *s;
2223         for (i = 0;i < SKINFRAME_HASH;i++)
2224         {
2225                 for (s = r_skinframe.hash[i];s;s = s->next)
2226                 {
2227                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2228                                 R_SkinFrame_PurgeSkinFrame(s);
2229                 }
2230         }
2231 }
2232
2233 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2234         skinframe_t *item;
2235         char basename[MAX_QPATH];
2236
2237         Image_StripImageExtension(name, basename, sizeof(basename));
2238
2239         if( last == NULL ) {
2240                 int hashindex;
2241                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2242                 item = r_skinframe.hash[hashindex];
2243         } else {
2244                 item = last->next;
2245         }
2246
2247         // linearly search through the hash bucket
2248         for( ; item ; item = item->next ) {
2249                 if( !strcmp( item->basename, basename ) ) {
2250                         return item;
2251                 }
2252         }
2253         return NULL;
2254 }
2255
2256 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2257 {
2258         skinframe_t *item;
2259         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2260         int hashindex;
2261         char basename[MAX_QPATH];
2262
2263         Image_StripImageExtension(name, basename, sizeof(basename));
2264
2265         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2266         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2267                 if (!strcmp(item->basename, basename) &&
2268                         item->textureflags == compareflags &&
2269                         item->comparewidth == comparewidth &&
2270                         item->compareheight == compareheight &&
2271                         item->comparecrc == comparecrc)
2272                         break;
2273
2274         if (!item)
2275         {
2276                 if (!add)
2277                         return NULL;
2278                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2279                 memset(item, 0, sizeof(*item));
2280                 strlcpy(item->basename, basename, sizeof(item->basename));
2281                 item->textureflags = compareflags;
2282                 item->comparewidth = comparewidth;
2283                 item->compareheight = compareheight;
2284                 item->comparecrc = comparecrc;
2285                 item->next = r_skinframe.hash[hashindex];
2286                 r_skinframe.hash[hashindex] = item;
2287         }
2288         else if (textureflags & TEXF_FORCE_RELOAD)
2289                 R_SkinFrame_PurgeSkinFrame(item);
2290
2291         R_SkinFrame_MarkUsed(item);
2292         return item;
2293 }
2294
2295 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2296         { \
2297                 unsigned long long avgcolor[5], wsum; \
2298                 int pix, comp, w; \
2299                 avgcolor[0] = 0; \
2300                 avgcolor[1] = 0; \
2301                 avgcolor[2] = 0; \
2302                 avgcolor[3] = 0; \
2303                 avgcolor[4] = 0; \
2304                 wsum = 0; \
2305                 for(pix = 0; pix < cnt; ++pix) \
2306                 { \
2307                         w = 0; \
2308                         for(comp = 0; comp < 3; ++comp) \
2309                                 w += getpixel; \
2310                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2311                         { \
2312                                 ++wsum; \
2313                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2314                                 w = getpixel; \
2315                                 for(comp = 0; comp < 3; ++comp) \
2316                                         avgcolor[comp] += getpixel * w; \
2317                                 avgcolor[3] += w; \
2318                         } \
2319                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2320                         avgcolor[4] += getpixel; \
2321                 } \
2322                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2323                         avgcolor[3] = 1; \
2324                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2325                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2326                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2327                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2328         }
2329
2330 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2331 {
2332         skinframe_t *skinframe;
2333
2334         if (cls.state == ca_dedicated)
2335                 return NULL;
2336
2337         // return an existing skinframe if already loaded
2338         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2339         if (skinframe && skinframe->base)
2340                 return skinframe;
2341
2342         // if the skinframe doesn't exist this will create it
2343         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2344 }
2345
2346 extern cvar_t gl_picmip;
2347 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2348 {
2349         int j;
2350         unsigned char *pixels;
2351         unsigned char *bumppixels;
2352         unsigned char *basepixels = NULL;
2353         int basepixels_width = 0;
2354         int basepixels_height = 0;
2355         rtexture_t *ddsbase = NULL;
2356         qboolean ddshasalpha = false;
2357         float ddsavgcolor[4];
2358         char basename[MAX_QPATH];
2359         int miplevel = R_PicmipForFlags(textureflags);
2360         int savemiplevel = miplevel;
2361         int mymiplevel;
2362         char vabuf[1024];
2363
2364         if (cls.state == ca_dedicated)
2365                 return NULL;
2366
2367         Image_StripImageExtension(name, basename, sizeof(basename));
2368
2369         // check for DDS texture file first
2370         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2371         {
2372                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2373                 if (basepixels == NULL && fallbacknotexture)
2374                         basepixels = Image_GenerateNoTexture();
2375                 if (basepixels == NULL)
2376                         return NULL;
2377         }
2378
2379         // FIXME handle miplevel
2380
2381         if (developer_loading.integer)
2382                 Con_Printf("loading skin \"%s\"\n", name);
2383
2384         // we've got some pixels to store, so really allocate this new texture now
2385         if (!skinframe)
2386                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2387         textureflags &= ~TEXF_FORCE_RELOAD;
2388         skinframe->stain = NULL;
2389         skinframe->merged = NULL;
2390         skinframe->base = NULL;
2391         skinframe->pants = NULL;
2392         skinframe->shirt = NULL;
2393         skinframe->nmap = NULL;
2394         skinframe->gloss = NULL;
2395         skinframe->glow = NULL;
2396         skinframe->fog = NULL;
2397         skinframe->reflect = NULL;
2398         skinframe->hasalpha = false;
2399         // we could store the q2animname here too
2400
2401         if (ddsbase)
2402         {
2403                 skinframe->base = ddsbase;
2404                 skinframe->hasalpha = ddshasalpha;
2405                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2406                 if (r_loadfog && skinframe->hasalpha)
2407                         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);
2408                 //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]);
2409         }
2410         else
2411         {
2412                 basepixels_width = image_width;
2413                 basepixels_height = image_height;
2414                 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);
2415                 if (textureflags & TEXF_ALPHA)
2416                 {
2417                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2418                         {
2419                                 if (basepixels[j] < 255)
2420                                 {
2421                                         skinframe->hasalpha = true;
2422                                         break;
2423                                 }
2424                         }
2425                         if (r_loadfog && skinframe->hasalpha)
2426                         {
2427                                 // has transparent pixels
2428                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2429                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2430                                 {
2431                                         pixels[j+0] = 255;
2432                                         pixels[j+1] = 255;
2433                                         pixels[j+2] = 255;
2434                                         pixels[j+3] = basepixels[j+3];
2435                                 }
2436                                 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);
2437                                 Mem_Free(pixels);
2438                         }
2439                 }
2440                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2441 #ifndef USE_GLES2
2442                 //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]);
2443                 if (r_savedds && skinframe->base)
2444                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2445                 if (r_savedds && skinframe->fog)
2446                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2447 #endif
2448         }
2449
2450         if (r_loaddds)
2451         {
2452                 mymiplevel = savemiplevel;
2453                 if (r_loadnormalmap)
2454                         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);
2455                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2456                 if (r_loadgloss)
2457                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2458                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2459                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2460                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2461         }
2462
2463         // _norm is the name used by tenebrae and has been adopted as standard
2464         if (r_loadnormalmap && skinframe->nmap == NULL)
2465         {
2466                 mymiplevel = savemiplevel;
2467                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2468                 {
2469                         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);
2470                         Mem_Free(pixels);
2471                         pixels = NULL;
2472                 }
2473                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2474                 {
2475                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2476                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2477                         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);
2478                         Mem_Free(pixels);
2479                         Mem_Free(bumppixels);
2480                 }
2481                 else if (r_shadow_bumpscale_basetexture.value > 0)
2482                 {
2483                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2484                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2485                         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);
2486                         Mem_Free(pixels);
2487                 }
2488 #ifndef USE_GLES2
2489                 if (r_savedds && skinframe->nmap)
2490                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2491 #endif
2492         }
2493
2494         // _luma is supported only for tenebrae compatibility
2495         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2496         // _glow is the preferred name
2497         mymiplevel = savemiplevel;
2498         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))))
2499         {
2500                 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);
2501 #ifndef USE_GLES2
2502                 if (r_savedds && skinframe->glow)
2503                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2504 #endif
2505                 Mem_Free(pixels);pixels = NULL;
2506         }
2507
2508         mymiplevel = savemiplevel;
2509         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2510         {
2511                 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);
2512 #ifndef USE_GLES2
2513                 if (r_savedds && skinframe->gloss)
2514                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2515 #endif
2516                 Mem_Free(pixels);
2517                 pixels = NULL;
2518         }
2519
2520         mymiplevel = savemiplevel;
2521         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2522         {
2523                 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);
2524 #ifndef USE_GLES2
2525                 if (r_savedds && skinframe->pants)
2526                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2527 #endif
2528                 Mem_Free(pixels);
2529                 pixels = NULL;
2530         }
2531
2532         mymiplevel = savemiplevel;
2533         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2534         {
2535                 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);
2536 #ifndef USE_GLES2
2537                 if (r_savedds && skinframe->shirt)
2538                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2539 #endif
2540                 Mem_Free(pixels);
2541                 pixels = NULL;
2542         }
2543
2544         mymiplevel = savemiplevel;
2545         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2546         {
2547                 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);
2548 #ifndef USE_GLES2
2549                 if (r_savedds && skinframe->reflect)
2550                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2551 #endif
2552                 Mem_Free(pixels);
2553                 pixels = NULL;
2554         }
2555
2556         if (basepixels)
2557                 Mem_Free(basepixels);
2558
2559         return skinframe;
2560 }
2561
2562 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2563 {
2564         int i;
2565         skinframe_t *skinframe;
2566         char vabuf[1024];
2567
2568         if (cls.state == ca_dedicated)
2569                 return NULL;
2570
2571         // if already loaded just return it, otherwise make a new skinframe
2572         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2573         if (skinframe->base)
2574                 return skinframe;
2575         textureflags &= ~TEXF_FORCE_RELOAD;
2576
2577         skinframe->stain = NULL;
2578         skinframe->merged = NULL;
2579         skinframe->base = NULL;
2580         skinframe->pants = NULL;
2581         skinframe->shirt = NULL;
2582         skinframe->nmap = NULL;
2583         skinframe->gloss = NULL;
2584         skinframe->glow = NULL;
2585         skinframe->fog = NULL;
2586         skinframe->reflect = NULL;
2587         skinframe->hasalpha = false;
2588
2589         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2590         if (!skindata)
2591                 return NULL;
2592
2593         if (developer_loading.integer)
2594                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2595
2596         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2597         {
2598                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2599                 unsigned char *b = a + width * height * 4;
2600                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2601                 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);
2602                 Mem_Free(a);
2603         }
2604         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2605         if (textureflags & TEXF_ALPHA)
2606         {
2607                 for (i = 3;i < width * height * 4;i += 4)
2608                 {
2609                         if (skindata[i] < 255)
2610                         {
2611                                 skinframe->hasalpha = true;
2612                                 break;
2613                         }
2614                 }
2615                 if (r_loadfog && skinframe->hasalpha)
2616                 {
2617                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2618                         memcpy(fogpixels, skindata, width * height * 4);
2619                         for (i = 0;i < width * height * 4;i += 4)
2620                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2621                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2622                         Mem_Free(fogpixels);
2623                 }
2624         }
2625
2626         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2627         //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]);
2628
2629         return skinframe;
2630 }
2631
2632 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2633 {
2634         int i;
2635         int featuresmask;
2636         skinframe_t *skinframe;
2637
2638         if (cls.state == ca_dedicated)
2639                 return NULL;
2640
2641         // if already loaded just return it, otherwise make a new skinframe
2642         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2643         if (skinframe->base)
2644                 return skinframe;
2645         //textureflags &= ~TEXF_FORCE_RELOAD;
2646
2647         skinframe->stain = NULL;
2648         skinframe->merged = NULL;
2649         skinframe->base = NULL;
2650         skinframe->pants = NULL;
2651         skinframe->shirt = NULL;
2652         skinframe->nmap = NULL;
2653         skinframe->gloss = NULL;
2654         skinframe->glow = NULL;
2655         skinframe->fog = NULL;
2656         skinframe->reflect = NULL;
2657         skinframe->hasalpha = false;
2658
2659         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2660         if (!skindata)
2661                 return NULL;
2662
2663         if (developer_loading.integer)
2664                 Con_Printf("loading quake skin \"%s\"\n", name);
2665
2666         // 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)
2667         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2668         memcpy(skinframe->qpixels, skindata, width*height);
2669         skinframe->qwidth = width;
2670         skinframe->qheight = height;
2671
2672         featuresmask = 0;
2673         for (i = 0;i < width * height;i++)
2674                 featuresmask |= palette_featureflags[skindata[i]];
2675
2676         skinframe->hasalpha = false;
2677         // fence textures
2678         if (name[0] == '{')
2679                 skinframe->hasalpha = true;
2680         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2681         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2682         skinframe->qgeneratemerged = true;
2683         skinframe->qgeneratebase = skinframe->qhascolormapping;
2684         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2685
2686         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2687         //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]);
2688
2689         return skinframe;
2690 }
2691
2692 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2693 {
2694         int width;
2695         int height;
2696         unsigned char *skindata;
2697         char vabuf[1024];
2698
2699         if (!skinframe->qpixels)
2700                 return;
2701
2702         if (!skinframe->qhascolormapping)
2703                 colormapped = false;
2704
2705         if (colormapped)
2706         {
2707                 if (!skinframe->qgeneratebase)
2708                         return;
2709         }
2710         else
2711         {
2712                 if (!skinframe->qgeneratemerged)
2713                         return;
2714         }
2715
2716         width = skinframe->qwidth;
2717         height = skinframe->qheight;
2718         skindata = skinframe->qpixels;
2719
2720         if (skinframe->qgeneratenmap)
2721         {
2722                 unsigned char *a, *b;
2723                 skinframe->qgeneratenmap = false;
2724                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2725                 b = a + width * height * 4;
2726                 // use either a custom palette or the quake palette
2727                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2728                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2729                 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);
2730                 Mem_Free(a);
2731         }
2732
2733         if (skinframe->qgenerateglow)
2734         {
2735                 skinframe->qgenerateglow = false;
2736                 if (skinframe->hasalpha) // fence textures
2737                         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
2738                 else
2739                         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
2740         }
2741
2742         if (colormapped)
2743         {
2744                 skinframe->qgeneratebase = false;
2745                 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);
2746                 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);
2747                 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);
2748         }
2749         else
2750         {
2751                 skinframe->qgeneratemerged = false;
2752                 if (skinframe->hasalpha) // fence textures
2753                         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);
2754                 else
2755                         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);
2756         }
2757
2758         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2759         {
2760                 Mem_Free(skinframe->qpixels);
2761                 skinframe->qpixels = NULL;
2762         }
2763 }
2764
2765 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)
2766 {
2767         int i;
2768         skinframe_t *skinframe;
2769         char vabuf[1024];
2770
2771         if (cls.state == ca_dedicated)
2772                 return NULL;
2773
2774         // if already loaded just return it, otherwise make a new skinframe
2775         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2776         if (skinframe->base)
2777                 return skinframe;
2778         textureflags &= ~TEXF_FORCE_RELOAD;
2779
2780         skinframe->stain = NULL;
2781         skinframe->merged = NULL;
2782         skinframe->base = NULL;
2783         skinframe->pants = NULL;
2784         skinframe->shirt = NULL;
2785         skinframe->nmap = NULL;
2786         skinframe->gloss = NULL;
2787         skinframe->glow = NULL;
2788         skinframe->fog = NULL;
2789         skinframe->reflect = NULL;
2790         skinframe->hasalpha = false;
2791
2792         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2793         if (!skindata)
2794                 return NULL;
2795
2796         if (developer_loading.integer)
2797                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2798
2799         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2800         if ((textureflags & TEXF_ALPHA) && alphapalette)
2801         {
2802                 for (i = 0;i < width * height;i++)
2803                 {
2804                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2805                         {
2806                                 skinframe->hasalpha = true;
2807                                 break;
2808                         }
2809                 }
2810                 if (r_loadfog && skinframe->hasalpha)
2811                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2812         }
2813
2814         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2815         //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]);
2816
2817         return skinframe;
2818 }
2819
2820 skinframe_t *R_SkinFrame_LoadMissing(void)
2821 {
2822         skinframe_t *skinframe;
2823
2824         if (cls.state == ca_dedicated)
2825                 return NULL;
2826
2827         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2828         skinframe->stain = NULL;
2829         skinframe->merged = NULL;
2830         skinframe->base = NULL;
2831         skinframe->pants = NULL;
2832         skinframe->shirt = NULL;
2833         skinframe->nmap = NULL;
2834         skinframe->gloss = NULL;
2835         skinframe->glow = NULL;
2836         skinframe->fog = NULL;
2837         skinframe->reflect = NULL;
2838         skinframe->hasalpha = false;
2839
2840         skinframe->avgcolor[0] = rand() / RAND_MAX;
2841         skinframe->avgcolor[1] = rand() / RAND_MAX;
2842         skinframe->avgcolor[2] = rand() / RAND_MAX;
2843         skinframe->avgcolor[3] = 1;
2844
2845         return skinframe;
2846 }
2847
2848 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2849 {
2850         int x, y;
2851         static unsigned char pix[16][16][4];
2852
2853         if (cls.state == ca_dedicated)
2854                 return NULL;
2855
2856         // this makes a light grey/dark grey checkerboard texture
2857         if (!pix[0][0][3])
2858         {
2859                 for (y = 0; y < 16; y++)
2860                 {
2861                         for (x = 0; x < 16; x++)
2862                         {
2863                                 if ((y < 8) ^ (x < 8))
2864                                 {
2865                                         pix[y][x][0] = 128;
2866                                         pix[y][x][1] = 128;
2867                                         pix[y][x][2] = 128;
2868                                         pix[y][x][3] = 255;
2869                                 }
2870                                 else
2871                                 {
2872                                         pix[y][x][0] = 64;
2873                                         pix[y][x][1] = 64;
2874                                         pix[y][x][2] = 64;
2875                                         pix[y][x][3] = 255;
2876                                 }
2877                         }
2878                 }
2879         }
2880
2881         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2882 }
2883
2884 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2885 {
2886         skinframe_t *skinframe;
2887         if (cls.state == ca_dedicated)
2888                 return NULL;
2889         // if already loaded just return it, otherwise make a new skinframe
2890         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2891         if (skinframe->base)
2892                 return skinframe;
2893         textureflags &= ~TEXF_FORCE_RELOAD;
2894         skinframe->stain = NULL;
2895         skinframe->merged = NULL;
2896         skinframe->base = NULL;
2897         skinframe->pants = NULL;
2898         skinframe->shirt = NULL;
2899         skinframe->nmap = NULL;
2900         skinframe->gloss = NULL;
2901         skinframe->glow = NULL;
2902         skinframe->fog = NULL;
2903         skinframe->reflect = NULL;
2904         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2905         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2906         if (!tex)
2907                 return NULL;
2908         if (developer_loading.integer)
2909                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2910         skinframe->base = skinframe->merged = tex;
2911         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2912         return skinframe;
2913 }
2914
2915 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2916 typedef struct suffixinfo_s
2917 {
2918         const char *suffix;
2919         qboolean flipx, flipy, flipdiagonal;
2920 }
2921 suffixinfo_t;
2922 static suffixinfo_t suffix[3][6] =
2923 {
2924         {
2925                 {"px",   false, false, false},
2926                 {"nx",   false, false, false},
2927                 {"py",   false, false, false},
2928                 {"ny",   false, false, false},
2929                 {"pz",   false, false, false},
2930                 {"nz",   false, false, false}
2931         },
2932         {
2933                 {"posx", false, false, false},
2934                 {"negx", false, false, false},
2935                 {"posy", false, false, false},
2936                 {"negy", false, false, false},
2937                 {"posz", false, false, false},
2938                 {"negz", false, false, false}
2939         },
2940         {
2941                 {"rt",    true, false,  true},
2942                 {"lf",   false,  true,  true},
2943                 {"ft",    true,  true, false},
2944                 {"bk",   false, false, false},
2945                 {"up",    true, false,  true},
2946                 {"dn",    true, false,  true}
2947         }
2948 };
2949
2950 static int componentorder[4] = {0, 1, 2, 3};
2951
2952 static rtexture_t *R_LoadCubemap(const char *basename)
2953 {
2954         int i, j, cubemapsize, forcefilter;
2955         unsigned char *cubemappixels, *image_buffer;
2956         rtexture_t *cubemaptexture;
2957         char name[256];
2958
2959         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2960         forcefilter = TEXF_FORCELINEAR;
2961         if (basename && basename[0] == '!')
2962         {
2963                 basename++;
2964                 forcefilter = TEXF_FORCENEAREST;
2965         }
2966         // must start 0 so the first loadimagepixels has no requested width/height
2967         cubemapsize = 0;
2968         cubemappixels = NULL;
2969         cubemaptexture = NULL;
2970         // keep trying different suffix groups (posx, px, rt) until one loads
2971         for (j = 0;j < 3 && !cubemappixels;j++)
2972         {
2973                 // load the 6 images in the suffix group
2974                 for (i = 0;i < 6;i++)
2975                 {
2976                         // generate an image name based on the base and and suffix
2977                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2978                         // load it
2979                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2980                         {
2981                                 // an image loaded, make sure width and height are equal
2982                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2983                                 {
2984                                         // if this is the first image to load successfully, allocate the cubemap memory
2985                                         if (!cubemappixels && image_width >= 1)
2986                                         {
2987                                                 cubemapsize = image_width;
2988                                                 // note this clears to black, so unavailable sides are black
2989                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2990                                         }
2991                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2992                                         if (cubemappixels)
2993                                                 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);
2994                                 }
2995                                 else
2996                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2997                                 // free the image
2998                                 Mem_Free(image_buffer);
2999                         }
3000                 }
3001         }
3002         // if a cubemap loaded, upload it
3003         if (cubemappixels)
3004         {
3005                 if (developer_loading.integer)
3006                         Con_Printf("loading cubemap \"%s\"\n", basename);
3007
3008                 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);
3009                 Mem_Free(cubemappixels);
3010         }
3011         else
3012         {
3013                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3014                 if (developer_loading.integer)
3015                 {
3016                         Con_Printf("(tried tried images ");
3017                         for (j = 0;j < 3;j++)
3018                                 for (i = 0;i < 6;i++)
3019                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3020                         Con_Print(" and was unable to find any of them).\n");
3021                 }
3022         }
3023         return cubemaptexture;
3024 }
3025
3026 rtexture_t *R_GetCubemap(const char *basename)
3027 {
3028         int i;
3029         for (i = 0;i < r_texture_numcubemaps;i++)
3030                 if (r_texture_cubemaps[i] != NULL)
3031                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
3032                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
3033         if (i >= MAX_CUBEMAPS || !r_main_mempool)
3034                 return r_texture_whitecube;
3035         r_texture_numcubemaps++;
3036         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
3037         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
3038         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
3039         return r_texture_cubemaps[i]->texture;
3040 }
3041
3042 static void R_Main_FreeViewCache(void)
3043 {
3044         if (r_refdef.viewcache.entityvisible)
3045                 Mem_Free(r_refdef.viewcache.entityvisible);
3046         if (r_refdef.viewcache.world_pvsbits)
3047                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3048         if (r_refdef.viewcache.world_leafvisible)
3049                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3050         if (r_refdef.viewcache.world_surfacevisible)
3051                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3052         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3053 }
3054
3055 static void R_Main_ResizeViewCache(void)
3056 {
3057         int numentities = r_refdef.scene.numentities;
3058         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3059         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3060         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3061         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3062         if (r_refdef.viewcache.maxentities < numentities)
3063         {
3064                 r_refdef.viewcache.maxentities = numentities;
3065                 if (r_refdef.viewcache.entityvisible)
3066                         Mem_Free(r_refdef.viewcache.entityvisible);
3067                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3068         }
3069         if (r_refdef.viewcache.world_numclusters != numclusters)
3070         {
3071                 r_refdef.viewcache.world_numclusters = numclusters;
3072                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3073                 if (r_refdef.viewcache.world_pvsbits)
3074                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3075                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3076         }
3077         if (r_refdef.viewcache.world_numleafs != numleafs)
3078         {
3079                 r_refdef.viewcache.world_numleafs = numleafs;
3080                 if (r_refdef.viewcache.world_leafvisible)
3081                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3082                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3083         }
3084         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3085         {
3086                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3087                 if (r_refdef.viewcache.world_surfacevisible)
3088                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3089                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3090         }
3091 }
3092
3093 extern rtexture_t *loadingscreentexture;
3094 static void gl_main_start(void)
3095 {
3096         loadingscreentexture = NULL;
3097         r_texture_blanknormalmap = NULL;
3098         r_texture_white = NULL;
3099         r_texture_grey128 = NULL;
3100         r_texture_black = NULL;
3101         r_texture_whitecube = NULL;
3102         r_texture_normalizationcube = NULL;
3103         r_texture_fogattenuation = NULL;
3104         r_texture_fogheighttexture = NULL;
3105         r_texture_gammaramps = NULL;
3106         r_texture_numcubemaps = 0;
3107         r_uniformbufferalignment = 32;
3108
3109         r_loaddds = r_texture_dds_load.integer != 0;
3110         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3111
3112         switch(vid.renderpath)
3113         {
3114         case RENDERPATH_GL32:
3115         case RENDERPATH_GLES2:
3116                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3117                 Cvar_SetValueQuick(&gl_combine, 1);
3118                 Cvar_SetValueQuick(&r_glsl, 1);
3119                 r_loadnormalmap = true;
3120                 r_loadgloss = true;
3121                 r_loadfog = false;
3122 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3123                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3124 #endif
3125                 break;
3126         }
3127
3128         R_AnimCache_Free();
3129         R_FrameData_Reset();
3130         R_BufferData_Reset();
3131
3132         r_numqueries = 0;
3133         r_maxqueries = 0;
3134         memset(r_queries, 0, sizeof(r_queries));
3135
3136         r_qwskincache = NULL;
3137         r_qwskincache_size = 0;
3138
3139         // due to caching of texture_t references, the collision cache must be reset
3140         Collision_Cache_Reset(true);
3141
3142         // set up r_skinframe loading system for textures
3143         memset(&r_skinframe, 0, sizeof(r_skinframe));
3144         r_skinframe.loadsequence = 1;
3145         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3146
3147         r_main_texturepool = R_AllocTexturePool();
3148         R_BuildBlankTextures();
3149         R_BuildNoTexture();
3150         R_BuildWhiteCube();
3151         R_BuildNormalizationCube();
3152         r_texture_fogattenuation = NULL;
3153         r_texture_fogheighttexture = NULL;
3154         r_texture_gammaramps = NULL;
3155         //r_texture_fogintensity = NULL;
3156         memset(&r_fb, 0, sizeof(r_fb));
3157         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3158         r_glsl_permutation = NULL;
3159         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3160         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3161         memset(&r_svbsp, 0, sizeof (r_svbsp));
3162
3163         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3164         r_texture_numcubemaps = 0;
3165
3166         r_refdef.fogmasktable_density = 0;
3167
3168 #ifdef __ANDROID__
3169         // For Steelstorm Android
3170         // FIXME CACHE the program and reload
3171         // FIXME see possible combinations for SS:BR android
3172         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3173         R_SetupShader_SetPermutationGLSL(0, 12);
3174         R_SetupShader_SetPermutationGLSL(0, 13);
3175         R_SetupShader_SetPermutationGLSL(0, 8388621);
3176         R_SetupShader_SetPermutationGLSL(3, 0);
3177         R_SetupShader_SetPermutationGLSL(3, 2048);
3178         R_SetupShader_SetPermutationGLSL(5, 0);
3179         R_SetupShader_SetPermutationGLSL(5, 2);
3180         R_SetupShader_SetPermutationGLSL(5, 2048);
3181         R_SetupShader_SetPermutationGLSL(5, 8388608);
3182         R_SetupShader_SetPermutationGLSL(11, 1);
3183         R_SetupShader_SetPermutationGLSL(11, 2049);
3184         R_SetupShader_SetPermutationGLSL(11, 8193);
3185         R_SetupShader_SetPermutationGLSL(11, 10241);
3186         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3187 #endif
3188 }
3189
3190 extern unsigned int r_shadow_occlusion_buf;
3191
3192 static void gl_main_shutdown(void)
3193 {
3194         R_RenderTarget_FreeUnused(true);
3195         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3196         R_AnimCache_Free();
3197         R_FrameData_Reset();
3198         R_BufferData_Reset();
3199
3200         R_Main_FreeViewCache();
3201
3202         switch(vid.renderpath)
3203         {
3204         case RENDERPATH_GL32:
3205         case RENDERPATH_GLES2:
3206 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3207                 if (r_maxqueries)
3208                         qglDeleteQueries(r_maxqueries, r_queries);
3209 #endif
3210                 break;
3211         }
3212         r_shadow_occlusion_buf = 0;
3213         r_numqueries = 0;
3214         r_maxqueries = 0;
3215         memset(r_queries, 0, sizeof(r_queries));
3216
3217         r_qwskincache = NULL;
3218         r_qwskincache_size = 0;
3219
3220         // clear out the r_skinframe state
3221         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3222         memset(&r_skinframe, 0, sizeof(r_skinframe));
3223
3224         if (r_svbsp.nodes)
3225                 Mem_Free(r_svbsp.nodes);
3226         memset(&r_svbsp, 0, sizeof (r_svbsp));
3227         R_FreeTexturePool(&r_main_texturepool);
3228         loadingscreentexture = NULL;
3229         r_texture_blanknormalmap = NULL;
3230         r_texture_white = NULL;
3231         r_texture_grey128 = NULL;
3232         r_texture_black = NULL;
3233         r_texture_whitecube = NULL;
3234         r_texture_normalizationcube = NULL;
3235         r_texture_fogattenuation = NULL;
3236         r_texture_fogheighttexture = NULL;
3237         r_texture_gammaramps = NULL;
3238         r_texture_numcubemaps = 0;
3239         //r_texture_fogintensity = NULL;
3240         memset(&r_fb, 0, sizeof(r_fb));
3241         R_GLSL_Restart_f(&cmd_client);
3242
3243         r_glsl_permutation = NULL;
3244         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3245         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3246 }
3247
3248 static void gl_main_newmap(void)
3249 {
3250         // FIXME: move this code to client
3251         char *entities, entname[MAX_QPATH];
3252         if (r_qwskincache)
3253                 Mem_Free(r_qwskincache);
3254         r_qwskincache = NULL;
3255         r_qwskincache_size = 0;
3256         if (cl.worldmodel)
3257         {
3258                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3259                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3260                 {
3261                         CL_ParseEntityLump(entities);
3262                         Mem_Free(entities);
3263                         return;
3264                 }
3265                 if (cl.worldmodel->brush.entities)
3266                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3267         }
3268         R_Main_FreeViewCache();
3269
3270         R_FrameData_Reset();
3271         R_BufferData_Reset();
3272 }
3273
3274 void GL_Main_Init(void)
3275 {
3276         int i;
3277         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3278         R_InitShaderModeInfo();
3279
3280         Cmd_AddCommand(CMD_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3281         Cmd_AddCommand(CMD_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3282         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3283         if (gamemode == GAME_NEHAHRA)
3284         {
3285                 Cvar_RegisterVariable (&gl_fogenable);
3286                 Cvar_RegisterVariable (&gl_fogdensity);
3287                 Cvar_RegisterVariable (&gl_fogred);
3288                 Cvar_RegisterVariable (&gl_foggreen);
3289                 Cvar_RegisterVariable (&gl_fogblue);
3290                 Cvar_RegisterVariable (&gl_fogstart);
3291                 Cvar_RegisterVariable (&gl_fogend);
3292                 Cvar_RegisterVariable (&gl_skyclip);
3293         }
3294         Cvar_RegisterVariable(&r_motionblur);
3295         Cvar_RegisterVariable(&r_damageblur);
3296         Cvar_RegisterVariable(&r_motionblur_averaging);
3297         Cvar_RegisterVariable(&r_motionblur_randomize);
3298         Cvar_RegisterVariable(&r_motionblur_minblur);
3299         Cvar_RegisterVariable(&r_motionblur_maxblur);
3300         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3301         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3302         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3303         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3304         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3305         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3306         Cvar_RegisterVariable(&r_depthfirst);
3307         Cvar_RegisterVariable(&r_useinfinitefarclip);
3308         Cvar_RegisterVariable(&r_farclip_base);
3309         Cvar_RegisterVariable(&r_farclip_world);
3310         Cvar_RegisterVariable(&r_nearclip);
3311         Cvar_RegisterVariable(&r_deformvertexes);
3312         Cvar_RegisterVariable(&r_transparent);
3313         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3314         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3315         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3316         Cvar_RegisterVariable(&r_showoverdraw);
3317         Cvar_RegisterVariable(&r_showbboxes);
3318         Cvar_RegisterVariable(&r_showbboxes_client);
3319         Cvar_RegisterVariable(&r_showsurfaces);
3320         Cvar_RegisterVariable(&r_showtris);
3321         Cvar_RegisterVariable(&r_shownormals);
3322         Cvar_RegisterVariable(&r_showlighting);
3323         Cvar_RegisterVariable(&r_showcollisionbrushes);
3324         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3325         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3326         Cvar_RegisterVariable(&r_showdisabledepthtest);
3327         Cvar_RegisterVariable(&r_showspriteedges);
3328         Cvar_RegisterVariable(&r_showparticleedges);
3329         Cvar_RegisterVariable(&r_drawportals);
3330         Cvar_RegisterVariable(&r_drawentities);
3331         Cvar_RegisterVariable(&r_draw2d);
3332         Cvar_RegisterVariable(&r_drawworld);
3333         Cvar_RegisterVariable(&r_cullentities_trace);
3334         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3335         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3336         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3337         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3338         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3339         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3340         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3341         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3342         Cvar_RegisterVariable(&r_sortentities);
3343         Cvar_RegisterVariable(&r_drawviewmodel);
3344         Cvar_RegisterVariable(&r_drawexteriormodel);
3345         Cvar_RegisterVariable(&r_speeds);
3346         Cvar_RegisterVariable(&r_fullbrights);
3347         Cvar_RegisterVariable(&r_wateralpha);
3348         Cvar_RegisterVariable(&r_dynamic);
3349         Cvar_RegisterVariable(&r_fullbright_directed);
3350         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3351         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3352         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3353         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3354         Cvar_RegisterVariable(&r_fullbright);
3355         Cvar_RegisterVariable(&r_shadows);
3356         Cvar_RegisterVariable(&r_shadows_darken);
3357         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3358         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3359         Cvar_RegisterVariable(&r_shadows_throwdistance);
3360         Cvar_RegisterVariable(&r_shadows_throwdirection);
3361         Cvar_RegisterVariable(&r_shadows_focus);
3362         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3363         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3364         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3365         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3366         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3367         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3368         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3369         Cvar_RegisterVariable(&r_fog_exp2);
3370         Cvar_RegisterVariable(&r_fog_clear);
3371         Cvar_RegisterVariable(&r_drawfog);
3372         Cvar_RegisterVariable(&r_transparentdepthmasking);
3373         Cvar_RegisterVariable(&r_transparent_sortmindist);
3374         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3375         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3376         Cvar_RegisterVariable(&r_texture_dds_load);
3377         Cvar_RegisterVariable(&r_texture_dds_save);
3378         Cvar_RegisterVariable(&r_textureunits);
3379         Cvar_RegisterVariable(&gl_combine);
3380         Cvar_RegisterVariable(&r_usedepthtextures);
3381         Cvar_RegisterVariable(&r_viewfbo);
3382         Cvar_RegisterVariable(&r_rendertarget_debug);
3383         Cvar_RegisterVariable(&r_viewscale);
3384         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3385         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3386         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3387         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3388         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3389         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3390         Cvar_RegisterVariable(&r_glsl);
3391         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3392         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3393         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3394         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3395         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3396         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3397         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3398         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3399         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3400         Cvar_RegisterVariable(&r_glsl_postprocess);
3401         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3402         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3403         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3404         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3405         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3406         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3407         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3408         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3409         Cvar_RegisterVariable(&r_celshading);
3410         Cvar_RegisterVariable(&r_celoutlines);
3411
3412         Cvar_RegisterVariable(&r_water);
3413         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3414         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3415         Cvar_RegisterVariable(&r_water_clippingplanebias);
3416         Cvar_RegisterVariable(&r_water_refractdistort);
3417         Cvar_RegisterVariable(&r_water_reflectdistort);
3418         Cvar_RegisterVariable(&r_water_scissormode);
3419         Cvar_RegisterVariable(&r_water_lowquality);
3420         Cvar_RegisterVariable(&r_water_hideplayer);
3421
3422         Cvar_RegisterVariable(&r_lerpsprites);
3423         Cvar_RegisterVariable(&r_lerpmodels);
3424         Cvar_RegisterVariable(&r_nolerp_list);
3425         Cvar_RegisterVariable(&r_lerplightstyles);
3426         Cvar_RegisterVariable(&r_waterscroll);
3427         Cvar_RegisterVariable(&r_bloom);
3428         Cvar_RegisterVariable(&r_colorfringe);
3429         Cvar_RegisterVariable(&r_bloom_colorscale);
3430         Cvar_RegisterVariable(&r_bloom_brighten);
3431         Cvar_RegisterVariable(&r_bloom_blur);
3432         Cvar_RegisterVariable(&r_bloom_resolution);
3433         Cvar_RegisterVariable(&r_bloom_colorexponent);
3434         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3435         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3436         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3437         Cvar_RegisterVariable(&r_hdr_glowintensity);
3438         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3439         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3440         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3441         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3442         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3443         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3444         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3445         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3446         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3447         Cvar_RegisterVariable(&developer_texturelogging);
3448         Cvar_RegisterVariable(&gl_lightmaps);
3449         Cvar_RegisterVariable(&r_test);
3450         Cvar_RegisterVariable(&r_batch_multidraw);
3451         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3452         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3453         Cvar_RegisterVariable(&r_glsl_skeletal);
3454         Cvar_RegisterVariable(&r_glsl_saturation);
3455         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3456         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3457         Cvar_RegisterVariable(&r_framedatasize);
3458         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3459                 Cvar_RegisterVariable(&r_buffermegs[i]);
3460         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3461         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3462                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3463 #ifdef DP_MOBILETOUCH
3464         // GLES devices have terrible depth precision in general, so...
3465         Cvar_SetValueQuick(&r_nearclip, 4);
3466         Cvar_SetValueQuick(&r_farclip_base, 4096);
3467         Cvar_SetValueQuick(&r_farclip_world, 0);
3468         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3469 #endif
3470         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3471 }
3472
3473 void Render_Init(void)
3474 {
3475         gl_backend_init();
3476         R_Textures_Init();
3477         GL_Main_Init();
3478         Font_Init();
3479         GL_Draw_Init();
3480         R_Shadow_Init();
3481         R_Sky_Init();
3482         GL_Surf_Init();
3483         Sbar_Init();
3484         R_Particles_Init();
3485         R_Explosion_Init();
3486         R_LightningBeams_Init();
3487         Mod_RenderInit();
3488 }
3489
3490 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3491 {
3492         int i;
3493         mplane_t *p;
3494         if (r_trippy.integer)
3495                 return false;
3496         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3497         {
3498                 p = r_refdef.view.frustum + i;
3499                 switch(p->signbits)
3500                 {
3501                 default:
3502                 case 0:
3503                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3504                                 return true;
3505                         break;
3506                 case 1:
3507                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3508                                 return true;
3509                         break;
3510                 case 2:
3511                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3512                                 return true;
3513                         break;
3514                 case 3:
3515                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3516                                 return true;
3517                         break;
3518                 case 4:
3519                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3520                                 return true;
3521                         break;
3522                 case 5:
3523                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3524                                 return true;
3525                         break;
3526                 case 6:
3527                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3528                                 return true;
3529                         break;
3530                 case 7:
3531                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3532                                 return true;
3533                         break;
3534                 }
3535         }
3536         return false;
3537 }
3538
3539 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3540 {
3541         int i;
3542         const mplane_t *p;
3543         if (r_trippy.integer)
3544                 return false;
3545         for (i = 0;i < numplanes;i++)
3546         {
3547                 p = planes + i;
3548                 switch(p->signbits)
3549                 {
3550                 default:
3551                 case 0:
3552                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3553                                 return true;
3554                         break;
3555                 case 1:
3556                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3557                                 return true;
3558                         break;
3559                 case 2:
3560                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3561                                 return true;
3562                         break;
3563                 case 3:
3564                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3565                                 return true;
3566                         break;
3567                 case 4:
3568                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3569                                 return true;
3570                         break;
3571                 case 5:
3572                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3573                                 return true;
3574                         break;
3575                 case 6:
3576                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3577                                 return true;
3578                         break;
3579                 case 7:
3580                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3581                                 return true;
3582                         break;
3583                 }
3584         }
3585         return false;
3586 }
3587
3588 //==================================================================================
3589
3590 // LadyHavoc: this stores temporary data used within the same frame
3591
3592 typedef struct r_framedata_mem_s
3593 {
3594         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3595         size_t size; // how much usable space
3596         size_t current; // how much space in use
3597         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3598         size_t wantedsize; // how much space was allocated
3599         unsigned char *data; // start of real data (16byte aligned)
3600 }
3601 r_framedata_mem_t;
3602
3603 static r_framedata_mem_t *r_framedata_mem;
3604
3605 void R_FrameData_Reset(void)
3606 {
3607         while (r_framedata_mem)
3608         {
3609                 r_framedata_mem_t *next = r_framedata_mem->purge;
3610                 Mem_Free(r_framedata_mem);
3611                 r_framedata_mem = next;
3612         }
3613 }
3614
3615 static void R_FrameData_Resize(qboolean mustgrow)
3616 {
3617         size_t wantedsize;
3618         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3619         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3620         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3621         {
3622                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3623                 newmem->wantedsize = wantedsize;
3624                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3625                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3626                 newmem->current = 0;
3627                 newmem->mark = 0;
3628                 newmem->purge = r_framedata_mem;
3629                 r_framedata_mem = newmem;
3630         }
3631 }
3632
3633 void R_FrameData_NewFrame(void)
3634 {
3635         R_FrameData_Resize(false);
3636         if (!r_framedata_mem)
3637                 return;
3638         // if we ran out of space on the last frame, free the old memory now
3639         while (r_framedata_mem->purge)
3640         {
3641                 // repeatedly remove the second item in the list, leaving only head
3642                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3643                 Mem_Free(r_framedata_mem->purge);
3644                 r_framedata_mem->purge = next;
3645         }
3646         // reset the current mem pointer
3647         r_framedata_mem->current = 0;
3648         r_framedata_mem->mark = 0;
3649 }
3650
3651 void *R_FrameData_Alloc(size_t size)
3652 {
3653         void *data;
3654         float newvalue;
3655
3656         // align to 16 byte boundary - the data pointer is already aligned, so we
3657         // only need to ensure the size of every allocation is also aligned
3658         size = (size + 15) & ~15;
3659
3660         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3661         {
3662                 // emergency - we ran out of space, allocate more memory
3663                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3664                 newvalue = r_framedatasize.value * 2.0f;
3665                 // 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
3666                 if (sizeof(size_t) >= 8)
3667                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3668                 else
3669                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3670                 // this might not be a growing it, but we'll allocate another buffer every time
3671                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3672                 R_FrameData_Resize(true);
3673         }
3674
3675         data = r_framedata_mem->data + r_framedata_mem->current;
3676         r_framedata_mem->current += size;
3677
3678         // count the usage for stats
3679         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3680         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3681
3682         return (void *)data;
3683 }
3684
3685 void *R_FrameData_Store(size_t size, void *data)
3686 {
3687         void *d = R_FrameData_Alloc(size);
3688         if (d && data)
3689                 memcpy(d, data, size);
3690         return d;
3691 }
3692
3693 void R_FrameData_SetMark(void)
3694 {
3695         if (!r_framedata_mem)
3696                 return;
3697         r_framedata_mem->mark = r_framedata_mem->current;
3698 }
3699
3700 void R_FrameData_ReturnToMark(void)
3701 {
3702         if (!r_framedata_mem)
3703                 return;
3704         r_framedata_mem->current = r_framedata_mem->mark;
3705 }
3706
3707 //==================================================================================
3708
3709 // avoid reusing the same buffer objects on consecutive frames
3710 #define R_BUFFERDATA_CYCLE 3
3711
3712 typedef struct r_bufferdata_buffer_s
3713 {
3714         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3715         size_t size; // how much usable space
3716         size_t current; // how much space in use
3717         r_meshbuffer_t *buffer; // the buffer itself
3718 }
3719 r_bufferdata_buffer_t;
3720
3721 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3722 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3723
3724 /// frees all dynamic buffers
3725 void R_BufferData_Reset(void)
3726 {
3727         int cycle, type;
3728         r_bufferdata_buffer_t **p, *mem;
3729         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3730         {
3731                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3732                 {
3733                         // free all buffers
3734                         p = &r_bufferdata_buffer[cycle][type];
3735                         while (*p)
3736                         {
3737                                 mem = *p;
3738                                 *p = (*p)->purge;
3739                                 if (mem->buffer)
3740                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3741                                 Mem_Free(mem);
3742                         }
3743                 }
3744         }
3745 }
3746
3747 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3748 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3749 {
3750         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3751         size_t size;
3752         float newvalue = r_buffermegs[type].value;
3753
3754         // increase the cvar if we have to (but only if we already have a mem)
3755         if (mustgrow && mem)
3756                 newvalue *= 2.0f;
3757         newvalue = bound(0.25f, newvalue, 256.0f);
3758         while (newvalue * 1024*1024 < minsize)
3759                 newvalue *= 2.0f;
3760
3761         // clamp the cvar to valid range
3762         newvalue = bound(0.25f, newvalue, 256.0f);
3763         if (r_buffermegs[type].value != newvalue)
3764                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3765
3766         // calculate size in bytes
3767         size = (size_t)(newvalue * 1024*1024);
3768         size = bound(131072, size, 256*1024*1024);
3769
3770         // allocate a new buffer if the size is different (purge old one later)
3771         // or if we were told we must grow the buffer
3772         if (!mem || mem->size != size || mustgrow)
3773         {
3774                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3775                 mem->size = size;
3776                 mem->current = 0;
3777                 if (type == R_BUFFERDATA_VERTEX)
3778                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3779                 else if (type == R_BUFFERDATA_INDEX16)
3780                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3781                 else if (type == R_BUFFERDATA_INDEX32)
3782                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3783                 else if (type == R_BUFFERDATA_UNIFORM)
3784                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3785                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3786                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3787         }
3788 }
3789
3790 void R_BufferData_NewFrame(void)
3791 {
3792         int type;
3793         r_bufferdata_buffer_t **p, *mem;
3794         // cycle to the next frame's buffers
3795         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3796         // if we ran out of space on the last time we used these buffers, free the old memory now
3797         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3798         {
3799                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3800                 {
3801                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3802                         // free all but the head buffer, this is how we recycle obsolete
3803                         // buffers after they are no longer in use
3804                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3805                         while (*p)
3806                         {
3807                                 mem = *p;
3808                                 *p = (*p)->purge;
3809                                 if (mem->buffer)
3810                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3811                                 Mem_Free(mem);
3812                         }
3813                         // reset the current offset
3814                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3815                 }
3816         }
3817 }
3818
3819 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3820 {
3821         r_bufferdata_buffer_t *mem;
3822         int offset = 0;
3823         int padsize;
3824
3825         *returnbufferoffset = 0;
3826
3827         // align size to a byte boundary appropriate for the buffer type, this
3828         // makes all allocations have aligned start offsets
3829         if (type == R_BUFFERDATA_UNIFORM)
3830                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3831         else
3832                 padsize = (datasize + 15) & ~15;
3833
3834         // if we ran out of space in this buffer we must allocate a new one
3835         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)
3836                 R_BufferData_Resize(type, true, padsize);
3837
3838         // if the resize did not give us enough memory, fail
3839         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)
3840                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3841
3842         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3843         offset = (int)mem->current;
3844         mem->current += padsize;
3845
3846         // upload the data to the buffer at the chosen offset
3847         if (offset == 0)
3848                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3849         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3850
3851         // count the usage for stats
3852         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3853         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3854
3855         // return the buffer offset
3856         *returnbufferoffset = offset;
3857
3858         return mem->buffer;
3859 }
3860
3861 //==================================================================================
3862
3863 // LadyHavoc: animcache originally written by Echon, rewritten since then
3864
3865 /**
3866  * Animation cache prevents re-generating mesh data for an animated model
3867  * multiple times in one frame for lighting, shadowing, reflections, etc.
3868  */
3869
3870 void R_AnimCache_Free(void)
3871 {
3872 }
3873
3874 void R_AnimCache_ClearCache(void)
3875 {
3876         int i;
3877         entity_render_t *ent;
3878
3879         for (i = 0;i < r_refdef.scene.numentities;i++)
3880         {
3881                 ent = r_refdef.scene.entities[i];
3882                 ent->animcache_vertex3f = NULL;
3883                 ent->animcache_vertex3f_vertexbuffer = NULL;
3884                 ent->animcache_vertex3f_bufferoffset = 0;
3885                 ent->animcache_normal3f = NULL;
3886                 ent->animcache_normal3f_vertexbuffer = NULL;
3887                 ent->animcache_normal3f_bufferoffset = 0;
3888                 ent->animcache_svector3f = NULL;
3889                 ent->animcache_svector3f_vertexbuffer = NULL;
3890                 ent->animcache_svector3f_bufferoffset = 0;
3891                 ent->animcache_tvector3f = NULL;
3892                 ent->animcache_tvector3f_vertexbuffer = NULL;
3893                 ent->animcache_tvector3f_bufferoffset = 0;
3894                 ent->animcache_skeletaltransform3x4 = NULL;
3895                 ent->animcache_skeletaltransform3x4buffer = NULL;
3896                 ent->animcache_skeletaltransform3x4offset = 0;
3897                 ent->animcache_skeletaltransform3x4size = 0;
3898         }
3899 }
3900
3901 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3902 {
3903         dp_model_t *model = ent->model;
3904         int numvertices;
3905
3906         // see if this ent is worth caching
3907         if (!model || !model->Draw || !model->AnimateVertices)
3908                 return false;
3909         // nothing to cache if it contains no animations and has no skeleton
3910         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3911                 return false;
3912         // see if it is already cached for gpuskeletal
3913         if (ent->animcache_skeletaltransform3x4)
3914                 return false;
3915         // see if it is already cached as a mesh
3916         if (ent->animcache_vertex3f)
3917         {
3918                 // check if we need to add normals or tangents
3919                 if (ent->animcache_normal3f)
3920                         wantnormals = false;
3921                 if (ent->animcache_svector3f)
3922                         wanttangents = false;
3923                 if (!wantnormals && !wanttangents)
3924                         return false;
3925         }
3926
3927         // check which kind of cache we need to generate
3928         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3929         {
3930                 // cache the skeleton so the vertex shader can use it
3931                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3932                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3933                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3934                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3935                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3936                 // note: this can fail if the buffer is at the grow limit
3937                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3938                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3939         }
3940         else if (ent->animcache_vertex3f)
3941         {
3942                 // mesh was already cached but we may need to add normals/tangents
3943                 // (this only happens with multiple views, reflections, cameras, etc)
3944                 if (wantnormals || wanttangents)
3945                 {
3946                         numvertices = model->surfmesh.num_vertices;
3947                         if (wantnormals)
3948                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3949                         if (wanttangents)
3950                         {
3951                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3952                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3953                         }
3954                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3955                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3956                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3957                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3958                 }
3959         }
3960         else
3961         {
3962                 // generate mesh cache
3963                 numvertices = model->surfmesh.num_vertices;
3964                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3965                 if (wantnormals)
3966                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3967                 if (wanttangents)
3968                 {
3969                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3970                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3971                 }
3972                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3973                 if (wantnormals || wanttangents)
3974                 {
3975                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3976                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3977                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3978                 }
3979                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3980                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3981                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3982         }
3983         return true;
3984 }
3985
3986 void R_AnimCache_CacheVisibleEntities(void)
3987 {
3988         int i;
3989
3990         // TODO: thread this
3991         // NOTE: R_PrepareRTLights() also caches entities
3992
3993         for (i = 0;i < r_refdef.scene.numentities;i++)
3994                 if (r_refdef.viewcache.entityvisible[i])
3995                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3996 }
3997
3998 //==================================================================================
3999
4000 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
4001 {
4002         long unsigned int i;
4003         int j;
4004         vec3_t eyemins, eyemaxs;
4005         vec3_t boxmins, boxmaxs;
4006         vec3_t padmins, padmaxs;
4007         vec3_t start;
4008         vec3_t end;
4009         dp_model_t *model = r_refdef.scene.worldmodel;
4010         static vec3_t positions[] = {
4011                 { 0.5f, 0.5f, 0.5f },
4012                 { 0.0f, 0.0f, 0.0f },
4013                 { 0.0f, 0.0f, 1.0f },
4014                 { 0.0f, 1.0f, 0.0f },
4015                 { 0.0f, 1.0f, 1.0f },
4016                 { 1.0f, 0.0f, 0.0f },
4017                 { 1.0f, 0.0f, 1.0f },
4018                 { 1.0f, 1.0f, 0.0f },
4019                 { 1.0f, 1.0f, 1.0f },
4020         };
4021
4022         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4023         if (numsamples < 0)
4024                 return true;
4025
4026         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4027         if (!r_refdef.view.usevieworiginculling)
4028                 return true;
4029
4030         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4031                 return true;
4032
4033         // expand the eye box a little
4034         eyemins[0] = eye[0] - eyejitter;
4035         eyemaxs[0] = eye[0] + eyejitter;
4036         eyemins[1] = eye[1] - eyejitter;
4037         eyemaxs[1] = eye[1] + eyejitter;
4038         eyemins[2] = eye[2] - eyejitter;
4039         eyemaxs[2] = eye[2] + eyejitter;
4040         // expand the box a little
4041         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4042         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4043         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4044         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4045         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4046         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4047         // make an even larger box for the acceptable area
4048         padmins[0] = boxmins[0] - pad;
4049         padmaxs[0] = boxmaxs[0] + pad;
4050         padmins[1] = boxmins[1] - pad;
4051         padmaxs[1] = boxmaxs[1] + pad;
4052         padmins[2] = boxmins[2] - pad;
4053         padmaxs[2] = boxmaxs[2] + pad;
4054
4055         // return true if eye overlaps enlarged box
4056         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4057                 return true;
4058
4059         // try specific positions in the box first - note that these can be cached
4060         if (r_cullentities_trace_entityocclusion.integer)
4061         {
4062                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4063                 {
4064                         trace_t trace;
4065                         VectorCopy(eye, start);
4066                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4067                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4068                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4069                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4070                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4071                         // not picky - if the trace ended anywhere in the box we're good
4072                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4073                                 return true;
4074                 }
4075         }
4076         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4077                 return true;
4078
4079         // try various random positions
4080         for (j = 0; j < numsamples; j++)
4081         {
4082                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4083                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4084                 if (r_cullentities_trace_entityocclusion.integer)
4085                 {
4086                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4087                         // not picky - if the trace ended anywhere in the box we're good
4088                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4089                                 return true;
4090                 }
4091                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4092                         return true;
4093         }
4094
4095         return false;
4096 }
4097
4098
4099 static void R_View_UpdateEntityVisible (void)
4100 {
4101         int i;
4102         int renderimask;
4103         int samples;
4104         entity_render_t *ent;
4105
4106         if (r_refdef.envmap || r_fb.water.hideplayer)
4107                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4108         else if (chase_active.integer || r_fb.water.renderingscene)
4109                 renderimask = RENDER_VIEWMODEL;
4110         else
4111                 renderimask = RENDER_EXTERIORMODEL;
4112         if (!r_drawviewmodel.integer)
4113                 renderimask |= RENDER_VIEWMODEL;
4114         if (!r_drawexteriormodel.integer)
4115                 renderimask |= RENDER_EXTERIORMODEL;
4116         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4117         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4118         {
4119                 // worldmodel can check visibility
4120                 for (i = 0;i < r_refdef.scene.numentities;i++)
4121                 {
4122                         ent = r_refdef.scene.entities[i];
4123                         if (!(ent->flags & renderimask))
4124                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4125                         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))
4126                                 r_refdef.viewcache.entityvisible[i] = true;
4127                 }
4128         }
4129         else
4130         {
4131                 // no worldmodel or it can't check visibility
4132                 for (i = 0;i < r_refdef.scene.numentities;i++)
4133                 {
4134                         ent = r_refdef.scene.entities[i];
4135                         if (!(ent->flags & renderimask))
4136                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4137                                 r_refdef.viewcache.entityvisible[i] = true;
4138                 }
4139         }
4140         if (r_cullentities_trace.integer)
4141         {
4142                 for (i = 0;i < r_refdef.scene.numentities;i++)
4143                 {
4144                         if (!r_refdef.viewcache.entityvisible[i])
4145                                 continue;
4146                         ent = r_refdef.scene.entities[i];
4147                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4148                         {
4149                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4150                                 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))
4151                                         ent->last_trace_visibility = host.realtime;
4152                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4153                                         r_refdef.viewcache.entityvisible[i] = 0;
4154                         }
4155                 }
4156         }
4157 }
4158
4159 /// only used if skyrendermasked, and normally returns false
4160 static int R_DrawBrushModelsSky (void)
4161 {
4162         int i, sky;
4163         entity_render_t *ent;
4164
4165         sky = false;
4166         for (i = 0;i < r_refdef.scene.numentities;i++)
4167         {
4168                 if (!r_refdef.viewcache.entityvisible[i])
4169                         continue;
4170                 ent = r_refdef.scene.entities[i];
4171                 if (!ent->model || !ent->model->DrawSky)
4172                         continue;
4173                 ent->model->DrawSky(ent);
4174                 sky = true;
4175         }
4176         return sky;
4177 }
4178
4179 static void R_DrawNoModel(entity_render_t *ent);
4180 static void R_DrawModels(void)
4181 {
4182         int i;
4183         entity_render_t *ent;
4184
4185         for (i = 0;i < r_refdef.scene.numentities;i++)
4186         {
4187                 if (!r_refdef.viewcache.entityvisible[i])
4188                         continue;
4189                 ent = r_refdef.scene.entities[i];
4190                 r_refdef.stats[r_stat_entities]++;
4191                 /*
4192                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4193                 {
4194                         vec3_t f, l, u, o;
4195                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4196                         Con_Printf("R_DrawModels\n");
4197                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4198                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4199                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4200                 }
4201                 */
4202                 if (ent->model && ent->model->Draw != NULL)
4203                         ent->model->Draw(ent);
4204                 else
4205                         R_DrawNoModel(ent);
4206         }
4207 }
4208
4209 static void R_DrawModelsDepth(void)
4210 {
4211         int i;
4212         entity_render_t *ent;
4213
4214         for (i = 0;i < r_refdef.scene.numentities;i++)
4215         {
4216                 if (!r_refdef.viewcache.entityvisible[i])
4217                         continue;
4218                 ent = r_refdef.scene.entities[i];
4219                 if (ent->model && ent->model->DrawDepth != NULL)
4220                         ent->model->DrawDepth(ent);
4221         }
4222 }
4223
4224 static void R_DrawModelsDebug(void)
4225 {
4226         int i;
4227         entity_render_t *ent;
4228
4229         for (i = 0;i < r_refdef.scene.numentities;i++)
4230         {
4231                 if (!r_refdef.viewcache.entityvisible[i])
4232                         continue;
4233                 ent = r_refdef.scene.entities[i];
4234                 if (ent->model && ent->model->DrawDebug != NULL)
4235                         ent->model->DrawDebug(ent);
4236         }
4237 }
4238
4239 static void R_DrawModelsAddWaterPlanes(void)
4240 {
4241         int i;
4242         entity_render_t *ent;
4243
4244         for (i = 0;i < r_refdef.scene.numentities;i++)
4245         {
4246                 if (!r_refdef.viewcache.entityvisible[i])
4247                         continue;
4248                 ent = r_refdef.scene.entities[i];
4249                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4250                         ent->model->DrawAddWaterPlanes(ent);
4251         }
4252 }
4253
4254 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}};
4255
4256 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4257 {
4258         if (r_hdr_irisadaptation.integer)
4259         {
4260                 vec3_t p;
4261                 vec3_t ambient;
4262                 vec3_t diffuse;
4263                 vec3_t diffusenormal;
4264                 vec3_t forward;
4265                 vec_t brightness = 0.0f;
4266                 vec_t goal;
4267                 vec_t current;
4268                 vec_t d;
4269                 int c;
4270                 VectorCopy(r_refdef.view.forward, forward);
4271                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4272                 {
4273                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4274                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4275                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4276                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4277                         d = DotProduct(forward, diffusenormal);
4278                         brightness += VectorLength(ambient);
4279                         if (d > 0)
4280                                 brightness += d * VectorLength(diffuse);
4281                 }
4282                 brightness *= 1.0f / c;
4283                 brightness += 0.00001f; // make sure it's never zero
4284                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4285                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4286                 current = r_hdr_irisadaptation_value.value;
4287                 if (current < goal)
4288                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4289                 else if (current > goal)
4290                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4291                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4292                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4293         }
4294         else if (r_hdr_irisadaptation_value.value != 1.0f)
4295                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4296 }
4297
4298 static void R_View_SetFrustum(const int *scissor)
4299 {
4300         int i;
4301         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4302         vec3_t forward, left, up, origin, v;
4303
4304         if(scissor)
4305         {
4306                 // flipped x coordinates (because x points left here)
4307                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4308                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4309                 // non-flipped y coordinates
4310                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4311                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4312         }
4313
4314         // we can't trust r_refdef.view.forward and friends in reflected scenes
4315         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4316
4317 #if 0
4318         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4319         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4320         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4321         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4322         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4323         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4324         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4325         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4326         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4327         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4328         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4329         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4330 #endif
4331
4332 #if 0
4333         zNear = r_refdef.nearclip;
4334         nudge = 1.0 - 1.0 / (1<<23);
4335         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4336         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4337         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4338         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4339         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4340         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4341         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4342         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4343 #endif
4344
4345
4346
4347 #if 0
4348         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4349         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4350         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4351         r_refdef.view.frustum[0].dist = m[15] - m[12];
4352
4353         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4354         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4355         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4356         r_refdef.view.frustum[1].dist = m[15] + m[12];
4357
4358         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4359         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4360         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4361         r_refdef.view.frustum[2].dist = m[15] - m[13];
4362
4363         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4364         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4365         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4366         r_refdef.view.frustum[3].dist = m[15] + m[13];
4367
4368         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4369         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4370         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4371         r_refdef.view.frustum[4].dist = m[15] - m[14];
4372
4373         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4374         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4375         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4376         r_refdef.view.frustum[5].dist = m[15] + m[14];
4377 #endif
4378
4379         if (r_refdef.view.useperspective)
4380         {
4381                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4382                 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]);
4383                 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]);
4384                 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]);
4385                 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]);
4386
4387                 // then the normals from the corners relative to origin
4388                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4389                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4390                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4391                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4392
4393                 // in a NORMAL view, forward cross left == up
4394                 // in a REFLECTED view, forward cross left == down
4395                 // so our cross products above need to be adjusted for a left handed coordinate system
4396                 CrossProduct(forward, left, v);
4397                 if(DotProduct(v, up) < 0)
4398                 {
4399                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4400                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4401                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4402                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4403                 }
4404
4405                 // Leaving those out was a mistake, those were in the old code, and they
4406                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4407                 // I couldn't reproduce it after adding those normalizations. --blub
4408                 VectorNormalize(r_refdef.view.frustum[0].normal);
4409                 VectorNormalize(r_refdef.view.frustum[1].normal);
4410                 VectorNormalize(r_refdef.view.frustum[2].normal);
4411                 VectorNormalize(r_refdef.view.frustum[3].normal);
4412
4413                 // make the corners absolute
4414                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4415                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4416                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4417                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4418
4419                 // one more normal
4420                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4421
4422                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4423                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4424                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4425                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4426                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4427         }
4428         else
4429         {
4430                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4431                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4432                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4433                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4434                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4435                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4436                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4437                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4438                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4439                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4440         }
4441         r_refdef.view.numfrustumplanes = 5;
4442
4443         if (r_refdef.view.useclipplane)
4444         {
4445                 r_refdef.view.numfrustumplanes = 6;
4446                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4447         }
4448
4449         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4450                 PlaneClassify(r_refdef.view.frustum + i);
4451
4452         // LadyHavoc: note to all quake engine coders, Quake had a special case
4453         // for 90 degrees which assumed a square view (wrong), so I removed it,
4454         // Quake2 has it disabled as well.
4455
4456         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4457         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4458         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4459         //PlaneClassify(&frustum[0]);
4460
4461         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4462         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4463         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4464         //PlaneClassify(&frustum[1]);
4465
4466         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4467         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4468         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4469         //PlaneClassify(&frustum[2]);
4470
4471         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4472         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4473         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4474         //PlaneClassify(&frustum[3]);
4475
4476         // nearclip plane
4477         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4478         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4479         //PlaneClassify(&frustum[4]);
4480 }
4481
4482 static void R_View_UpdateWithScissor(const int *myscissor)
4483 {
4484         R_Main_ResizeViewCache();
4485         R_View_SetFrustum(myscissor);
4486         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4487         R_View_UpdateEntityVisible();
4488 }
4489
4490 static void R_View_Update(void)
4491 {
4492         R_Main_ResizeViewCache();
4493         R_View_SetFrustum(NULL);
4494         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4495         R_View_UpdateEntityVisible();
4496 }
4497
4498 float viewscalefpsadjusted = 1.0f;
4499
4500 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4501 {
4502         const float *customclipplane = NULL;
4503         float plane[4];
4504         int /*rtwidth,*/ rtheight;
4505         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4506         {
4507                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4508                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4509                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4510                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4511                         dist = r_refdef.view.clipplane.dist;
4512                 plane[0] = r_refdef.view.clipplane.normal[0];
4513                 plane[1] = r_refdef.view.clipplane.normal[1];
4514                 plane[2] = r_refdef.view.clipplane.normal[2];
4515                 plane[3] = -dist;
4516                 customclipplane = plane;
4517         }
4518
4519         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4520         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4521
4522         if (!r_refdef.view.useperspective)
4523                 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);
4524         else if (vid.stencil && r_useinfinitefarclip.integer)
4525                 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);
4526         else
4527                 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);
4528         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4529         R_SetViewport(&r_refdef.view.viewport);
4530 }
4531
4532 void R_EntityMatrix(const matrix4x4_t *matrix)
4533 {
4534         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4535         {
4536                 gl_modelmatrixchanged = false;
4537                 gl_modelmatrix = *matrix;
4538                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4539                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4540                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4541                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4542                 CHECKGLERROR
4543                 switch(vid.renderpath)
4544                 {
4545                 case RENDERPATH_GL32:
4546                 case RENDERPATH_GLES2:
4547                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4548                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4549                         break;
4550                 }
4551         }
4552 }
4553
4554 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4555 {
4556         r_viewport_t viewport;
4557
4558         CHECKGLERROR
4559
4560         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4561         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4562         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4563         R_SetViewport(&viewport);
4564         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4565         GL_Color(1, 1, 1, 1);
4566         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4567         GL_BlendFunc(GL_ONE, GL_ZERO);
4568         GL_ScissorTest(false);
4569         GL_DepthMask(false);
4570         GL_DepthRange(0, 1);
4571         GL_DepthTest(false);
4572         GL_DepthFunc(GL_LEQUAL);
4573         R_EntityMatrix(&identitymatrix);
4574         R_Mesh_ResetTextureState();
4575         GL_PolygonOffset(0, 0);
4576         switch(vid.renderpath)
4577         {
4578         case RENDERPATH_GL32:
4579         case RENDERPATH_GLES2:
4580                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4581                 break;
4582         }
4583         GL_CullFace(GL_NONE);
4584
4585         CHECKGLERROR
4586 }
4587
4588 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4589 {
4590         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4591 }
4592
4593 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4594 {
4595         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4596         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4597         GL_Color(1, 1, 1, 1);
4598         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4599         GL_BlendFunc(GL_ONE, GL_ZERO);
4600         GL_ScissorTest(true);
4601         GL_DepthMask(true);
4602         GL_DepthRange(0, 1);
4603         GL_DepthTest(true);
4604         GL_DepthFunc(GL_LEQUAL);
4605         R_EntityMatrix(&identitymatrix);
4606         R_Mesh_ResetTextureState();
4607         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4608         switch(vid.renderpath)
4609         {
4610         case RENDERPATH_GL32:
4611         case RENDERPATH_GLES2:
4612                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4613                 break;
4614         }
4615         GL_CullFace(r_refdef.view.cullface_back);
4616 }
4617
4618 /*
4619 ================
4620 R_RenderView_UpdateViewVectors
4621 ================
4622 */
4623 void R_RenderView_UpdateViewVectors(void)
4624 {
4625         // break apart the view matrix into vectors for various purposes
4626         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4627         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4628         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4629         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4630         // make an inverted copy of the view matrix for tracking sprites
4631         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4632 }
4633
4634 void R_RenderTarget_FreeUnused(qboolean force)
4635 {
4636         unsigned int i, j, end;
4637         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4638         for (i = 0; i < end; i++)
4639         {
4640                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4641                 // free resources for rendertargets that have not been used for a while
4642                 // (note: this check is run after the frame render, so any targets used
4643                 // this frame will not be affected even at low framerates)
4644                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4645                 {
4646                         if (r->fbo)
4647                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4648                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4649                                 if (r->colortexture[j])
4650                                         R_FreeTexture(r->colortexture[j]);
4651                         if (r->depthtexture)
4652                                 R_FreeTexture(r->depthtexture);
4653                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4654                 }
4655         }
4656 }
4657
4658 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4659 {
4660         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4661         x1 = x * iw;
4662         x2 = (x + w) * iw;
4663         y1 = (th - y) * ih;
4664         y2 = (th - y - h) * ih;
4665         texcoord2f[0] = x1;
4666         texcoord2f[2] = x2;
4667         texcoord2f[4] = x2;
4668         texcoord2f[6] = x1;
4669         texcoord2f[1] = y1;
4670         texcoord2f[3] = y1;
4671         texcoord2f[5] = y2;
4672         texcoord2f[7] = y2;
4673 }
4674
4675 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4676 {
4677         unsigned int i, j, end;
4678         r_rendertarget_t *r = NULL;
4679         char vabuf[256];
4680         // first try to reuse an existing slot if possible
4681         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4682         for (i = 0; i < end; i++)
4683         {
4684                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4685                 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)
4686                         break;
4687         }
4688         if (i == end)
4689         {
4690                 // no unused exact match found, so we have to make one in the first unused slot
4691                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4692                 r->texturewidth = texturewidth;
4693                 r->textureheight = textureheight;
4694                 r->colortextype[0] = colortextype0;
4695                 r->colortextype[1] = colortextype1;
4696                 r->colortextype[2] = colortextype2;
4697                 r->colortextype[3] = colortextype3;
4698                 r->depthtextype = depthtextype;
4699                 r->depthisrenderbuffer = depthisrenderbuffer;
4700                 for (j = 0; j < 4; j++)
4701                         if (r->colortextype[j])
4702                                 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);
4703                 if (r->depthtextype)
4704                 {
4705                         if (r->depthisrenderbuffer)
4706                                 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);
4707                         else
4708                                 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);
4709                 }
4710                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4711         }
4712         r_refdef.stats[r_stat_rendertargets_used]++;
4713         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4714         r->lastusetime = host.realtime;
4715         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4716         return r;
4717 }
4718
4719 static void R_Water_StartFrame(int viewwidth, int viewheight)
4720 {
4721         int waterwidth, waterheight;
4722
4723         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4724                 return;
4725
4726         // set waterwidth and waterheight to the water resolution that will be
4727         // used (often less than the screen resolution for faster rendering)
4728         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4729         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4730
4731         if (!r_water.integer || r_showsurfaces.integer)
4732                 waterwidth = waterheight = 0;
4733
4734         // set up variables that will be used in shader setup
4735         r_fb.water.waterwidth = waterwidth;
4736         r_fb.water.waterheight = waterheight;
4737         r_fb.water.texturewidth = waterwidth;
4738         r_fb.water.textureheight = waterheight;
4739         r_fb.water.camerawidth = waterwidth;
4740         r_fb.water.cameraheight = waterheight;
4741         r_fb.water.screenscale[0] = 0.5f;
4742         r_fb.water.screenscale[1] = 0.5f;
4743         r_fb.water.screencenter[0] = 0.5f;
4744         r_fb.water.screencenter[1] = 0.5f;
4745         r_fb.water.enabled = waterwidth != 0;
4746
4747         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4748         r_fb.water.numwaterplanes = 0;
4749 }
4750
4751 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4752 {
4753         int planeindex, bestplaneindex, vertexindex;
4754         vec3_t mins, maxs, normal, center, v, n;
4755         vec_t planescore, bestplanescore;
4756         mplane_t plane;
4757         r_waterstate_waterplane_t *p;
4758         texture_t *t = R_GetCurrentTexture(surface->texture);
4759
4760         rsurface.texture = t;
4761         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4762         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4763         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4764                 return;
4765         // average the vertex normals, find the surface bounds (after deformvertexes)
4766         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4767         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4768         VectorCopy(n, normal);
4769         VectorCopy(v, mins);
4770         VectorCopy(v, maxs);
4771         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4772         {
4773                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4774                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4775                 VectorAdd(normal, n, normal);
4776                 mins[0] = min(mins[0], v[0]);
4777                 mins[1] = min(mins[1], v[1]);
4778                 mins[2] = min(mins[2], v[2]);
4779                 maxs[0] = max(maxs[0], v[0]);
4780                 maxs[1] = max(maxs[1], v[1]);
4781                 maxs[2] = max(maxs[2], v[2]);
4782         }
4783         VectorNormalize(normal);
4784         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4785
4786         VectorCopy(normal, plane.normal);
4787         VectorNormalize(plane.normal);
4788         plane.dist = DotProduct(center, plane.normal);
4789         PlaneClassify(&plane);
4790         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4791         {
4792                 // skip backfaces (except if nocullface is set)
4793 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4794 //                      return;
4795                 VectorNegate(plane.normal, plane.normal);
4796                 plane.dist *= -1;
4797                 PlaneClassify(&plane);
4798         }
4799
4800
4801         // find a matching plane if there is one
4802         bestplaneindex = -1;
4803         bestplanescore = 1048576.0f;
4804         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4805         {
4806                 if(p->camera_entity == t->camera_entity)
4807                 {
4808                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4809                         if (bestplaneindex < 0 || bestplanescore > planescore)
4810                         {
4811                                 bestplaneindex = planeindex;
4812                                 bestplanescore = planescore;
4813                         }
4814                 }
4815         }
4816         planeindex = bestplaneindex;
4817
4818         // if this surface does not fit any known plane rendered this frame, add one
4819         if (planeindex < 0 || bestplanescore > 0.001f)
4820         {
4821                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4822                 {
4823                         // store the new plane
4824                         planeindex = r_fb.water.numwaterplanes++;
4825                         p = r_fb.water.waterplanes + planeindex;
4826                         p->plane = plane;
4827                         // clear materialflags and pvs
4828                         p->materialflags = 0;
4829                         p->pvsvalid = false;
4830                         p->camera_entity = t->camera_entity;
4831                         VectorCopy(mins, p->mins);
4832                         VectorCopy(maxs, p->maxs);
4833                 }
4834                 else
4835                 {
4836                         // We're totally screwed.
4837                         return;
4838                 }
4839         }
4840         else
4841         {
4842                 // merge mins/maxs when we're adding this surface to the plane
4843                 p = r_fb.water.waterplanes + planeindex;
4844                 p->mins[0] = min(p->mins[0], mins[0]);
4845                 p->mins[1] = min(p->mins[1], mins[1]);
4846                 p->mins[2] = min(p->mins[2], mins[2]);
4847                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4848                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4849                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4850         }
4851         // merge this surface's materialflags into the waterplane
4852         p->materialflags |= t->currentmaterialflags;
4853         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4854         {
4855                 // merge this surface's PVS into the waterplane
4856                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4857                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4858                 {
4859                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4860                         p->pvsvalid = true;
4861                 }
4862         }
4863 }
4864
4865 extern cvar_t r_drawparticles;
4866 extern cvar_t r_drawdecals;
4867
4868 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4869 {
4870         int myscissor[4];
4871         r_refdef_view_t originalview;
4872         r_refdef_view_t myview;
4873         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;
4874         r_waterstate_waterplane_t *p;
4875         vec3_t visorigin;
4876         r_rendertarget_t *rt;
4877
4878         originalview = r_refdef.view;
4879
4880         // lowquality hack, temporarily shut down some cvars and restore afterwards
4881         qualityreduction = r_water_lowquality.integer;
4882         if (qualityreduction > 0)
4883         {
4884                 if (qualityreduction >= 1)
4885                 {
4886                         old_r_shadows = r_shadows.integer;
4887                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4888                         old_r_dlight = r_shadow_realtime_dlight.integer;
4889                         Cvar_SetValueQuick(&r_shadows, 0);
4890                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4891                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4892                 }
4893                 if (qualityreduction >= 2)
4894                 {
4895                         old_r_dynamic = r_dynamic.integer;
4896                         old_r_particles = r_drawparticles.integer;
4897                         old_r_decals = r_drawdecals.integer;
4898                         Cvar_SetValueQuick(&r_dynamic, 0);
4899                         Cvar_SetValueQuick(&r_drawparticles, 0);
4900                         Cvar_SetValueQuick(&r_drawdecals, 0);
4901                 }
4902         }
4903
4904         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4905         {
4906                 p->rt_reflection = NULL;
4907                 p->rt_refraction = NULL;
4908                 p->rt_camera = NULL;
4909         }
4910
4911         // render views
4912         r_refdef.view = originalview;
4913         r_refdef.view.showdebug = false;
4914         r_refdef.view.width = r_fb.water.waterwidth;
4915         r_refdef.view.height = r_fb.water.waterheight;
4916         r_refdef.view.useclipplane = true;
4917         myview = r_refdef.view;
4918         r_fb.water.renderingscene = true;
4919         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4920         {
4921                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4922                         continue;
4923
4924                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4925                 {
4926                         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);
4927                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4928                                 goto error;
4929                         r_refdef.view = myview;
4930                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4931                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4932                         if(r_water_scissormode.integer)
4933                         {
4934                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4935                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4936                                 {
4937                                         p->rt_reflection = NULL;
4938                                         p->rt_refraction = NULL;
4939                                         p->rt_camera = NULL;
4940                                         continue;
4941                                 }
4942                         }
4943
4944                         r_refdef.view.clipplane = p->plane;
4945                         // reflected view origin may be in solid, so don't cull with it
4946                         r_refdef.view.usevieworiginculling = false;
4947                         // reverse the cullface settings for this render
4948                         r_refdef.view.cullface_front = GL_FRONT;
4949                         r_refdef.view.cullface_back = GL_BACK;
4950                         // combined pvs (based on what can be seen from each surface center)
4951                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4952                         {
4953                                 r_refdef.view.usecustompvs = true;
4954                                 if (p->pvsvalid)
4955                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4956                                 else
4957                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4958                         }
4959
4960                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4961                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4962                         GL_ScissorTest(false);
4963                         R_ClearScreen(r_refdef.fogenabled);
4964                         GL_ScissorTest(true);
4965                         if(r_water_scissormode.integer & 2)
4966                                 R_View_UpdateWithScissor(myscissor);
4967                         else
4968                                 R_View_Update();
4969                         R_AnimCache_CacheVisibleEntities();
4970                         if(r_water_scissormode.integer & 1)
4971                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4972                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4973
4974                         r_fb.water.hideplayer = false;
4975                         p->rt_reflection = rt;
4976                 }
4977
4978                 // render the normal view scene and copy into texture
4979                 // (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)
4980                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4981                 {
4982                         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);
4983                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4984                                 goto error;
4985                         r_refdef.view = myview;
4986                         if(r_water_scissormode.integer)
4987                         {
4988                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4989                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4990                                 {
4991                                         p->rt_reflection = NULL;
4992                                         p->rt_refraction = NULL;
4993                                         p->rt_camera = NULL;
4994                                         continue;
4995                                 }
4996                         }
4997
4998                         // combined pvs (based on what can be seen from each surface center)
4999                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
5000                         {
5001                                 r_refdef.view.usecustompvs = true;
5002                                 if (p->pvsvalid)
5003                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5004                                 else
5005                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5006                         }
5007
5008                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5009
5010                         r_refdef.view.clipplane = p->plane;
5011                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5012                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5013
5014                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5015                         {
5016                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5017                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5018                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5019                                 R_RenderView_UpdateViewVectors();
5020                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5021                                 {
5022                                         r_refdef.view.usecustompvs = true;
5023                                         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);
5024                                 }
5025                         }
5026
5027                         PlaneClassify(&r_refdef.view.clipplane);
5028
5029                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5030                         GL_ScissorTest(false);
5031                         R_ClearScreen(r_refdef.fogenabled);
5032                         GL_ScissorTest(true);
5033                         if(r_water_scissormode.integer & 2)
5034                                 R_View_UpdateWithScissor(myscissor);
5035                         else
5036                                 R_View_Update();
5037                         R_AnimCache_CacheVisibleEntities();
5038                         if(r_water_scissormode.integer & 1)
5039                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5040                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5041
5042                         r_fb.water.hideplayer = false;
5043                         p->rt_refraction = rt;
5044                 }
5045                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5046                 {
5047                         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);
5048                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5049                                 goto error;
5050                         r_refdef.view = myview;
5051
5052                         r_refdef.view.clipplane = p->plane;
5053                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5054                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5055
5056                         r_refdef.view.width = r_fb.water.camerawidth;
5057                         r_refdef.view.height = r_fb.water.cameraheight;
5058                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5059                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5060                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5061                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5062
5063                         if(p->camera_entity)
5064                         {
5065                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5066                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5067                         }
5068
5069                         // note: all of the view is used for displaying... so
5070                         // there is no use in scissoring
5071
5072                         // reverse the cullface settings for this render
5073                         r_refdef.view.cullface_front = GL_FRONT;
5074                         r_refdef.view.cullface_back = GL_BACK;
5075                         // also reverse the view matrix
5076                         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
5077                         R_RenderView_UpdateViewVectors();
5078                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5079                         {
5080                                 r_refdef.view.usecustompvs = true;
5081                                 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);
5082                         }
5083                         
5084                         // camera needs no clipplane
5085                         r_refdef.view.useclipplane = false;
5086                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5087                         r_refdef.view.usevieworiginculling = false;
5088
5089                         PlaneClassify(&r_refdef.view.clipplane);
5090
5091                         r_fb.water.hideplayer = false;
5092
5093                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5094                         GL_ScissorTest(false);
5095                         R_ClearScreen(r_refdef.fogenabled);
5096                         GL_ScissorTest(true);
5097                         R_View_Update();
5098                         R_AnimCache_CacheVisibleEntities();
5099                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5100
5101                         r_fb.water.hideplayer = false;
5102                         p->rt_camera = rt;
5103                 }
5104
5105         }
5106         r_fb.water.renderingscene = false;
5107         r_refdef.view = originalview;
5108         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5109         R_View_Update();
5110         R_AnimCache_CacheVisibleEntities();
5111         goto finish;
5112 error:
5113         r_refdef.view = originalview;
5114         r_fb.water.renderingscene = false;
5115         Cvar_SetValueQuick(&r_water, 0);
5116         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5117 finish:
5118         // lowquality hack, restore cvars
5119         if (qualityreduction > 0)
5120         {
5121                 if (qualityreduction >= 1)
5122                 {
5123                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5124                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5125                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5126                 }
5127                 if (qualityreduction >= 2)
5128                 {
5129                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5130                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5131                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5132                 }
5133         }
5134 }
5135
5136 static void R_Bloom_StartFrame(void)
5137 {
5138         int screentexturewidth, screentextureheight;
5139         textype_t textype = TEXTYPE_COLORBUFFER;
5140         double scale;
5141
5142         // clear the pointers to rendertargets from last frame as they're stale
5143         r_fb.rt_screen = NULL;
5144         r_fb.rt_bloom = NULL;
5145
5146         switch (vid.renderpath)
5147         {
5148         case RENDERPATH_GL32:
5149                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5150                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5151                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5152                 break;
5153         case RENDERPATH_GLES2:
5154                 r_fb.usedepthtextures = false;
5155                 break;
5156         }
5157
5158         if (r_viewscale_fpsscaling.integer)
5159         {
5160                 double actualframetime;
5161                 double targetframetime;
5162                 double adjust;
5163                 actualframetime = r_refdef.lastdrawscreentime;
5164                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5165                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5166                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5167                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5168                 {
5169                         if (adjust > 0)
5170                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5171                         else
5172                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5173                 }
5174                 viewscalefpsadjusted += adjust;
5175                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5176         }
5177         else
5178                 viewscalefpsadjusted = 1.0f;
5179
5180         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5181         if (vid.samples)
5182                 scale *= sqrt(vid.samples); // supersampling
5183         scale = bound(0.03125f, scale, 4.0f);
5184         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5185         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5186         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5187         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5188
5189         // set bloomwidth and bloomheight to the bloom resolution that will be
5190         // used (often less than the screen resolution for faster rendering)
5191         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5192         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5193         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5194         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5195         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5196
5197         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))
5198         {
5199                 Cvar_SetValueQuick(&r_bloom, 0);
5200                 Cvar_SetValueQuick(&r_motionblur, 0);
5201                 Cvar_SetValueQuick(&r_damageblur, 0);
5202         }
5203         if (!r_bloom.integer)
5204                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5205
5206         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5207         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5208         {
5209                 if (r_fb.ghosttexture)
5210                         R_FreeTexture(r_fb.ghosttexture);
5211                 r_fb.ghosttexture = NULL;
5212
5213                 r_fb.screentexturewidth = screentexturewidth;
5214                 r_fb.screentextureheight = screentextureheight;
5215                 r_fb.textype = textype;
5216
5217                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5218                 {
5219                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5220                                 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);
5221                         r_fb.ghosttexture_valid = false;
5222                 }
5223         }
5224
5225         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5226
5227         r_refdef.view.clear = true;
5228 }
5229
5230 static void R_Bloom_MakeTexture(void)
5231 {
5232         int x, range, dir;
5233         float xoffset, yoffset, r, brighten;
5234         float colorscale = r_bloom_colorscale.value;
5235         r_viewport_t bloomviewport;
5236         r_rendertarget_t *prev, *cur;
5237         textype_t textype = r_fb.rt_screen->colortextype[0];
5238
5239         r_refdef.stats[r_stat_bloom]++;
5240
5241         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5242
5243         // scale down screen texture to the bloom texture size
5244         CHECKGLERROR
5245         prev = r_fb.rt_screen;
5246         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5247         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5248         R_SetViewport(&bloomviewport);
5249         GL_CullFace(GL_NONE);
5250         GL_DepthTest(false);
5251         GL_BlendFunc(GL_ONE, GL_ZERO);
5252         GL_Color(colorscale, colorscale, colorscale, 1);
5253         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5254         // TODO: do boxfilter scale-down in shader?
5255         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5256         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5257         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5258         // we now have a properly scaled bloom image
5259
5260         // multiply bloom image by itself as many times as desired to darken it
5261         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5262         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5263         {
5264                 prev = cur;
5265                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5266                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5267                 x *= 2;
5268                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5269                 if(x <= 2)
5270                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5271                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5272                 GL_Color(1,1,1,1); // no fix factor supported here
5273                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5274                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5275                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5276                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5277         }
5278         CHECKGLERROR
5279
5280         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5281         brighten = r_bloom_brighten.value;
5282         brighten = sqrt(brighten);
5283         if(range >= 1)
5284                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5285
5286         for (dir = 0;dir < 2;dir++)
5287         {
5288                 prev = cur;
5289                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5290                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5291                 // blend on at multiple vertical offsets to achieve a vertical blur
5292                 // TODO: do offset blends using GLSL
5293                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5294                 CHECKGLERROR
5295                 GL_BlendFunc(GL_ONE, GL_ZERO);
5296                 CHECKGLERROR
5297                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5298                 CHECKGLERROR
5299                 for (x = -range;x <= range;x++)
5300                 {
5301                         if (!dir){xoffset = 0;yoffset = x;}
5302                         else {xoffset = x;yoffset = 0;}
5303                         xoffset /= (float)prev->texturewidth;
5304                         yoffset /= (float)prev->textureheight;
5305                         // compute a texcoord array with the specified x and y offset
5306                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5307                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5308                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5309                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5310                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5311                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5312                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5313                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5314                         // this r value looks like a 'dot' particle, fading sharply to
5315                         // black at the edges
5316                         // (probably not realistic but looks good enough)
5317                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5318                         //r = brighten/(range*2+1);
5319                         r = brighten / (range * 2 + 1);
5320                         if(range >= 1)
5321                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5322                         if (r <= 0)
5323                                 continue;
5324                         CHECKGLERROR
5325                         GL_Color(r, r, r, 1);
5326                         CHECKGLERROR
5327                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5328                         CHECKGLERROR
5329                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5330                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5331                         CHECKGLERROR
5332                         GL_BlendFunc(GL_ONE, GL_ONE);
5333                         CHECKGLERROR
5334                 }
5335         }
5336
5337         // now we have the bloom image, so keep track of it
5338         r_fb.rt_bloom = cur;
5339 }
5340
5341 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5342 {
5343         uint64_t permutation;
5344         float uservecs[4][4];
5345         rtexture_t *viewtexture;
5346         rtexture_t *bloomtexture;
5347
5348         R_EntityMatrix(&identitymatrix);
5349
5350         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5351         {
5352                 // declare variables
5353                 float blur_factor, blur_mouseaccel, blur_velocity;
5354                 static float blur_average; 
5355                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5356
5357                 // set a goal for the factoring
5358                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5359                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5360                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5361                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5362                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5363                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5364
5365                 // from the goal, pick an averaged value between goal and last value
5366                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5367                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5368
5369                 // enforce minimum amount of blur 
5370                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5371
5372                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5373
5374                 // calculate values into a standard alpha
5375                 cl.motionbluralpha = 1 - exp(-
5376                                 (
5377                                         (r_motionblur.value * blur_factor / 80)
5378                                         +
5379                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5380                                 )
5381                                 /
5382                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5383                                 );
5384
5385                 // randomization for the blur value to combat persistent ghosting
5386                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5387                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5388
5389                 // apply the blur
5390                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5391                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5392                 {
5393                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5394                         GL_Color(1, 1, 1, cl.motionbluralpha);
5395                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5396                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5397                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5398                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5399                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5400                 }
5401
5402                 // updates old view angles for next pass
5403                 VectorCopy(cl.viewangles, blur_oldangles);
5404
5405                 // copy view into the ghost texture
5406                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5407                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5408                 r_fb.ghosttexture_valid = true;
5409         }
5410
5411         if (r_fb.bloomwidth)
5412         {
5413                 // make the bloom texture
5414                 R_Bloom_MakeTexture();
5415         }
5416
5417 #if _MSC_VER >= 1400
5418 #define sscanf sscanf_s
5419 #endif
5420         memset(uservecs, 0, sizeof(uservecs));
5421         if (r_glsl_postprocess_uservec1_enable.integer)
5422                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5423         if (r_glsl_postprocess_uservec2_enable.integer)
5424                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5425         if (r_glsl_postprocess_uservec3_enable.integer)
5426                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5427         if (r_glsl_postprocess_uservec4_enable.integer)
5428                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5429
5430         // render to the screen fbo
5431         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5432         GL_Color(1, 1, 1, 1);
5433         GL_BlendFunc(GL_ONE, GL_ZERO);
5434
5435         viewtexture = r_fb.rt_screen->colortexture[0];
5436         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5437
5438         if (r_rendertarget_debug.integer >= 0)
5439         {
5440                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5441                 if (rt && rt->colortexture[0])
5442                 {
5443                         viewtexture = rt->colortexture[0];
5444                         bloomtexture = NULL;
5445                 }
5446         }
5447
5448         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5449         switch(vid.renderpath)
5450         {
5451         case RENDERPATH_GL32:
5452         case RENDERPATH_GLES2:
5453                 permutation =
5454                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5455                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5456                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5457                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5458                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5459                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5460                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5461                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5462                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5463                 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]);
5464                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5465                 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]);
5466                 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]);
5467                 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]);
5468                 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]);
5469                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5470                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5471                 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);
5472                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5473                 break;
5474         }
5475         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5476         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5477 }
5478
5479 matrix4x4_t r_waterscrollmatrix;
5480
5481 void R_UpdateFog(void)
5482 {
5483         // Nehahra fog
5484         if (gamemode == GAME_NEHAHRA)
5485         {
5486                 if (gl_fogenable.integer)
5487                 {
5488                         r_refdef.oldgl_fogenable = true;
5489                         r_refdef.fog_density = gl_fogdensity.value;
5490                         r_refdef.fog_red = gl_fogred.value;
5491                         r_refdef.fog_green = gl_foggreen.value;
5492                         r_refdef.fog_blue = gl_fogblue.value;
5493                         r_refdef.fog_alpha = 1;
5494                         r_refdef.fog_start = 0;
5495                         r_refdef.fog_end = gl_skyclip.value;
5496                         r_refdef.fog_height = 1<<30;
5497                         r_refdef.fog_fadedepth = 128;
5498                 }
5499                 else if (r_refdef.oldgl_fogenable)
5500                 {
5501                         r_refdef.oldgl_fogenable = false;
5502                         r_refdef.fog_density = 0;
5503                         r_refdef.fog_red = 0;
5504                         r_refdef.fog_green = 0;
5505                         r_refdef.fog_blue = 0;
5506                         r_refdef.fog_alpha = 0;
5507                         r_refdef.fog_start = 0;
5508                         r_refdef.fog_end = 0;
5509                         r_refdef.fog_height = 1<<30;
5510                         r_refdef.fog_fadedepth = 128;
5511                 }
5512         }
5513
5514         // fog parms
5515         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5516         r_refdef.fog_start = max(0, r_refdef.fog_start);
5517         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5518
5519         if (r_refdef.fog_density && r_drawfog.integer)
5520         {
5521                 r_refdef.fogenabled = true;
5522                 // this is the point where the fog reaches 0.9986 alpha, which we
5523                 // consider a good enough cutoff point for the texture
5524                 // (0.9986 * 256 == 255.6)
5525                 if (r_fog_exp2.integer)
5526                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5527                 else
5528                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5529                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5530                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5531                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5532                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5533                         R_BuildFogHeightTexture();
5534                 // fog color was already set
5535                 // update the fog texture
5536                 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)
5537                         R_BuildFogTexture();
5538                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5539                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5540         }
5541         else
5542                 r_refdef.fogenabled = false;
5543
5544         // fog color
5545         if (r_refdef.fog_density)
5546         {
5547                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5548                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5549                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5550
5551                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5552                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5553                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5554                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5555
5556                 {
5557                         vec3_t fogvec;
5558                         VectorCopy(r_refdef.fogcolor, fogvec);
5559                         //   color.rgb *= ContrastBoost * SceneBrightness;
5560                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5561                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5562                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5563                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5564                 }
5565         }
5566 }
5567
5568 void R_UpdateVariables(void)
5569 {
5570         R_Textures_Frame();
5571
5572         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5573
5574         r_refdef.farclip = r_farclip_base.value;
5575         if (r_refdef.scene.worldmodel)
5576                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5577         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5578
5579         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5580                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5581         r_refdef.polygonfactor = 0;
5582         r_refdef.polygonoffset = 0;
5583
5584         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5585         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5586         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5587         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5588         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5589         if (r_refdef.scene.worldmodel)
5590         {
5591                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5592         }
5593         if (r_showsurfaces.integer)
5594         {
5595                 r_refdef.scene.rtworld = false;
5596                 r_refdef.scene.rtworldshadows = false;
5597                 r_refdef.scene.rtdlight = false;
5598                 r_refdef.scene.rtdlightshadows = false;
5599                 r_refdef.scene.lightmapintensity = 0;
5600         }
5601
5602         r_gpuskeletal = false;
5603         switch(vid.renderpath)
5604         {
5605         case RENDERPATH_GL32:
5606                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5607         case RENDERPATH_GLES2:
5608                 if(!vid_gammatables_trivial)
5609                 {
5610                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5611                         {
5612                                 // build GLSL gamma texture
5613 #define RAMPWIDTH 256
5614                                 unsigned short ramp[RAMPWIDTH * 3];
5615                                 unsigned char rampbgr[RAMPWIDTH][4];
5616                                 int i;
5617
5618                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5619
5620                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5621                                 for(i = 0; i < RAMPWIDTH; ++i)
5622                                 {
5623                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5624                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5625                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5626                                         rampbgr[i][3] = 0;
5627                                 }
5628                                 if (r_texture_gammaramps)
5629                                 {
5630                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5631                                 }
5632                                 else
5633                                 {
5634                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5635                                 }
5636                         }
5637                 }
5638                 else
5639                 {
5640                         // remove GLSL gamma texture
5641                 }
5642                 break;
5643         }
5644 }
5645
5646 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5647 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5648 /*
5649 ================
5650 R_SelectScene
5651 ================
5652 */
5653 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5654         if( scenetype != r_currentscenetype ) {
5655                 // store the old scenetype
5656                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5657                 r_currentscenetype = scenetype;
5658                 // move in the new scene
5659                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5660         }
5661 }
5662
5663 /*
5664 ================
5665 R_GetScenePointer
5666 ================
5667 */
5668 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5669 {
5670         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5671         if( scenetype == r_currentscenetype ) {
5672                 return &r_refdef.scene;
5673         } else {
5674                 return &r_scenes_store[ scenetype ];
5675         }
5676 }
5677
5678 static int R_SortEntities_Compare(const void *ap, const void *bp)
5679 {
5680         const entity_render_t *a = *(const entity_render_t **)ap;
5681         const entity_render_t *b = *(const entity_render_t **)bp;
5682
5683         // 1. compare model
5684         if(a->model < b->model)
5685                 return -1;
5686         if(a->model > b->model)
5687                 return +1;
5688
5689         // 2. compare skin
5690         // TODO possibly calculate the REAL skinnum here first using
5691         // skinscenes?
5692         if(a->skinnum < b->skinnum)
5693                 return -1;
5694         if(a->skinnum > b->skinnum)
5695                 return +1;
5696
5697         // everything we compared is equal
5698         return 0;
5699 }
5700 static void R_SortEntities(void)
5701 {
5702         // below or equal 2 ents, sorting never gains anything
5703         if(r_refdef.scene.numentities <= 2)
5704                 return;
5705         // sort
5706         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5707 }
5708
5709 /*
5710 ================
5711 R_RenderView
5712 ================
5713 */
5714 extern cvar_t r_shadow_bouncegrid;
5715 extern cvar_t v_isometric;
5716 extern void V_MakeViewIsometric(void);
5717 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5718 {
5719         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5720         int viewfbo = 0;
5721         rtexture_t *viewdepthtexture = NULL;
5722         rtexture_t *viewcolortexture = NULL;
5723         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5724
5725         // finish any 2D rendering that was queued
5726         DrawQ_Finish();
5727
5728         if (r_timereport_active)
5729                 R_TimeReport("start");
5730         r_textureframe++; // used only by R_GetCurrentTexture
5731         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5732
5733         if(R_CompileShader_CheckStaticParms())
5734                 R_GLSL_Restart_f(&cmd_client);
5735
5736         if (!r_drawentities.integer)
5737                 r_refdef.scene.numentities = 0;
5738         else if (r_sortentities.integer)
5739                 R_SortEntities();
5740
5741         R_AnimCache_ClearCache();
5742
5743         /* adjust for stereo display */
5744         if(R_Stereo_Active())
5745         {
5746                 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);
5747                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5748         }
5749
5750         if (r_refdef.view.isoverlay)
5751         {
5752                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5753                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5754                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5755                 R_TimeReport("depthclear");
5756
5757                 r_refdef.view.showdebug = false;
5758
5759                 r_fb.water.enabled = false;
5760                 r_fb.water.numwaterplanes = 0;
5761
5762                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5763
5764                 r_refdef.view.matrix = originalmatrix;
5765
5766                 CHECKGLERROR
5767                 return;
5768         }
5769
5770         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5771         {
5772                 r_refdef.view.matrix = originalmatrix;
5773                 return;
5774         }
5775
5776         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5777         if (v_isometric.integer && r_refdef.view.ismain)
5778                 V_MakeViewIsometric();
5779
5780         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5781
5782         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5783                 // in sRGB fallback, behave similar to true sRGB: convert this
5784                 // value from linear to sRGB
5785                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5786
5787         R_RenderView_UpdateViewVectors();
5788
5789         R_Shadow_UpdateWorldLightSelection();
5790
5791         // this will set up r_fb.rt_screen
5792         R_Bloom_StartFrame();
5793
5794         // apply bloom brightness offset
5795         if(r_fb.rt_bloom)
5796                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5797
5798         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5799         if (r_fb.rt_screen)
5800         {
5801                 viewfbo = r_fb.rt_screen->fbo;
5802                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5803                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5804                 viewx = 0;
5805                 viewy = 0;
5806                 viewwidth = r_fb.rt_screen->texturewidth;
5807                 viewheight = r_fb.rt_screen->textureheight;
5808         }
5809
5810         R_Water_StartFrame(viewwidth, viewheight);
5811
5812         CHECKGLERROR
5813         if (r_timereport_active)
5814                 R_TimeReport("viewsetup");
5815
5816         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5817
5818         // clear the whole fbo every frame - otherwise the driver will consider
5819         // it to be an inter-frame texture and stall in multi-gpu configurations
5820         if (r_fb.rt_screen)
5821                 GL_ScissorTest(false);
5822         R_ClearScreen(r_refdef.fogenabled);
5823         if (r_timereport_active)
5824                 R_TimeReport("viewclear");
5825
5826         r_refdef.view.clear = true;
5827
5828         r_refdef.view.showdebug = true;
5829
5830         R_View_Update();
5831         if (r_timereport_active)
5832                 R_TimeReport("visibility");
5833
5834         R_AnimCache_CacheVisibleEntities();
5835         if (r_timereport_active)
5836                 R_TimeReport("animcache");
5837
5838         R_Shadow_UpdateBounceGridTexture();
5839         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5840
5841         r_fb.water.numwaterplanes = 0;
5842         if (r_fb.water.enabled)
5843                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5844
5845         // for the actual view render we use scissoring a fair amount, so scissor
5846         // test needs to be on
5847         if (r_fb.rt_screen)
5848                 GL_ScissorTest(true);
5849         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5850         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5851         r_fb.water.numwaterplanes = 0;
5852
5853         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5854         GL_ScissorTest(false);
5855
5856         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5857         if (r_timereport_active)
5858                 R_TimeReport("blendview");
5859
5860         r_refdef.view.matrix = originalmatrix;
5861
5862         CHECKGLERROR
5863
5864         // go back to 2d rendering
5865         DrawQ_Start();
5866 }
5867
5868 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5869 {
5870         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5871         {
5872                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5873                 if (r_timereport_active)
5874                         R_TimeReport("waterworld");
5875         }
5876
5877         // don't let sound skip if going slow
5878         if (r_refdef.scene.extraupdate)
5879                 S_ExtraUpdate ();
5880
5881         R_DrawModelsAddWaterPlanes();
5882         if (r_timereport_active)
5883                 R_TimeReport("watermodels");
5884
5885         if (r_fb.water.numwaterplanes)
5886         {
5887                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5888                 if (r_timereport_active)
5889                         R_TimeReport("waterscenes");
5890         }
5891 }
5892
5893 extern cvar_t cl_locs_show;
5894 static void R_DrawLocs(void);
5895 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5896 static void R_DrawModelDecals(void);
5897 extern qboolean r_shadow_usingdeferredprepass;
5898 extern int r_shadow_shadowmapatlas_modelshadows_size;
5899 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5900 {
5901         qboolean shadowmapping = false;
5902
5903         if (r_timereport_active)
5904                 R_TimeReport("beginscene");
5905
5906         r_refdef.stats[r_stat_renders]++;
5907
5908         R_UpdateFog();
5909
5910         // don't let sound skip if going slow
5911         if (r_refdef.scene.extraupdate)
5912                 S_ExtraUpdate ();
5913
5914         R_MeshQueue_BeginScene();
5915
5916         R_SkyStartFrame();
5917
5918         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);
5919
5920         if (r_timereport_active)
5921                 R_TimeReport("skystartframe");
5922
5923         if (cl.csqc_vidvars.drawworld)
5924         {
5925                 // don't let sound skip if going slow
5926                 if (r_refdef.scene.extraupdate)
5927                         S_ExtraUpdate ();
5928
5929                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5930                 {
5931                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5932                         if (r_timereport_active)
5933                                 R_TimeReport("worldsky");
5934                 }
5935
5936                 if (R_DrawBrushModelsSky() && r_timereport_active)
5937                         R_TimeReport("bmodelsky");
5938
5939                 if (skyrendermasked && skyrenderlater)
5940                 {
5941                         // we have to force off the water clipping plane while rendering sky
5942                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5943                         R_Sky();
5944                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5945                         if (r_timereport_active)
5946                                 R_TimeReport("sky");
5947                 }
5948         }
5949
5950         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5951         r_shadow_viewfbo = viewfbo;
5952         r_shadow_viewdepthtexture = viewdepthtexture;
5953         r_shadow_viewcolortexture = viewcolortexture;
5954         r_shadow_viewx = viewx;
5955         r_shadow_viewy = viewy;
5956         r_shadow_viewwidth = viewwidth;
5957         r_shadow_viewheight = viewheight;
5958
5959         R_Shadow_PrepareModelShadows();
5960         R_Shadow_PrepareLights();
5961         if (r_timereport_active)
5962                 R_TimeReport("preparelights");
5963
5964         // render all the shadowmaps that will be used for this view
5965         shadowmapping = R_Shadow_ShadowMappingEnabled();
5966         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5967         {
5968                 R_Shadow_DrawShadowMaps();
5969                 if (r_timereport_active)
5970                         R_TimeReport("shadowmaps");
5971         }
5972
5973         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5974         if (r_shadow_usingdeferredprepass)
5975                 R_Shadow_DrawPrepass();
5976
5977         // now we begin the forward pass of the view render
5978         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5979         {
5980                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5981                 if (r_timereport_active)
5982                         R_TimeReport("worlddepth");
5983         }
5984         if (r_depthfirst.integer >= 2)
5985         {
5986                 R_DrawModelsDepth();
5987                 if (r_timereport_active)
5988                         R_TimeReport("modeldepth");
5989         }
5990
5991         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5992         {
5993                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5994                 if (r_timereport_active)
5995                         R_TimeReport("world");
5996         }
5997
5998         // don't let sound skip if going slow
5999         if (r_refdef.scene.extraupdate)
6000                 S_ExtraUpdate ();
6001
6002         R_DrawModels();
6003         if (r_timereport_active)
6004                 R_TimeReport("models");
6005
6006         // don't let sound skip if going slow
6007         if (r_refdef.scene.extraupdate)
6008                 S_ExtraUpdate ();
6009
6010         if (!r_shadow_usingdeferredprepass)
6011         {
6012                 R_Shadow_DrawLights();
6013                 if (r_timereport_active)
6014                         R_TimeReport("rtlights");
6015         }
6016
6017         // don't let sound skip if going slow
6018         if (r_refdef.scene.extraupdate)
6019                 S_ExtraUpdate ();
6020
6021         if (cl.csqc_vidvars.drawworld)
6022         {
6023                 R_DrawModelDecals();
6024                 if (r_timereport_active)
6025                         R_TimeReport("modeldecals");
6026
6027                 R_DrawParticles();
6028                 if (r_timereport_active)
6029                         R_TimeReport("particles");
6030
6031                 R_DrawExplosions();
6032                 if (r_timereport_active)
6033                         R_TimeReport("explosions");
6034         }
6035
6036         if (r_refdef.view.showdebug)
6037         {
6038                 if (cl_locs_show.integer)
6039                 {
6040                         R_DrawLocs();
6041                         if (r_timereport_active)
6042                                 R_TimeReport("showlocs");
6043                 }
6044
6045                 if (r_drawportals.integer)
6046                 {
6047                         R_DrawPortals();
6048                         if (r_timereport_active)
6049                                 R_TimeReport("portals");
6050                 }
6051
6052                 if (r_showbboxes_client.value > 0)
6053                 {
6054                         R_DrawEntityBBoxes(CLVM_prog);
6055                         if (r_timereport_active)
6056                                 R_TimeReport("clbboxes");
6057                 }
6058                 if (r_showbboxes.value > 0)
6059                 {
6060                         R_DrawEntityBBoxes(SVVM_prog);
6061                         if (r_timereport_active)
6062                                 R_TimeReport("svbboxes");
6063                 }
6064         }
6065
6066         if (r_transparent.integer)
6067         {
6068                 R_MeshQueue_RenderTransparent();
6069                 if (r_timereport_active)
6070                         R_TimeReport("drawtrans");
6071         }
6072
6073         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))
6074         {
6075                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6076                 if (r_timereport_active)
6077                         R_TimeReport("worlddebug");
6078                 R_DrawModelsDebug();
6079                 if (r_timereport_active)
6080                         R_TimeReport("modeldebug");
6081         }
6082
6083         if (cl.csqc_vidvars.drawworld)
6084         {
6085                 R_Shadow_DrawCoronas();
6086                 if (r_timereport_active)
6087                         R_TimeReport("coronas");
6088         }
6089
6090         // don't let sound skip if going slow
6091         if (r_refdef.scene.extraupdate)
6092                 S_ExtraUpdate ();
6093 }
6094
6095 static const unsigned short bboxelements[36] =
6096 {
6097         5, 1, 3, 5, 3, 7,
6098         6, 2, 0, 6, 0, 4,
6099         7, 3, 2, 7, 2, 6,
6100         4, 0, 1, 4, 1, 5,
6101         4, 5, 7, 4, 7, 6,
6102         1, 0, 2, 1, 2, 3,
6103 };
6104
6105 #define BBOXEDGES 13
6106 static const float bboxedges[BBOXEDGES][6] = 
6107 {
6108         // whole box
6109         { 0, 0, 0, 1, 1, 1 },
6110         // bottom edges
6111         { 0, 0, 0, 0, 1, 0 },
6112         { 0, 0, 0, 1, 0, 0 },
6113         { 0, 1, 0, 1, 1, 0 },
6114         { 1, 0, 0, 1, 1, 0 },
6115         // top edges
6116         { 0, 0, 1, 0, 1, 1 },
6117         { 0, 0, 1, 1, 0, 1 },
6118         { 0, 1, 1, 1, 1, 1 },
6119         { 1, 0, 1, 1, 1, 1 },
6120         // vertical edges
6121         { 0, 0, 0, 0, 0, 1 },
6122         { 1, 0, 0, 1, 0, 1 },
6123         { 0, 1, 0, 0, 1, 1 },
6124         { 1, 1, 0, 1, 1, 1 },
6125 };
6126
6127 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6128 {
6129         int numvertices = BBOXEDGES * 8;
6130         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6131         int numtriangles = BBOXEDGES * 12;
6132         unsigned short elements[BBOXEDGES * 36];
6133         int i, edge;
6134         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6135
6136         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6137
6138         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6139         GL_DepthMask(false);
6140         GL_DepthRange(0, 1);
6141         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6142
6143         for (edge = 0; edge < BBOXEDGES; edge++)
6144         {
6145                 for (i = 0; i < 3; i++)
6146                 {
6147                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6148                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6149                 }
6150                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6151                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6152                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6153                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6154                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6155                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6156                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6157                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6158                 for (i = 0; i < 36; i++)
6159                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6160         }
6161         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6162         if (r_refdef.fogenabled)
6163         {
6164                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6165                 {
6166                         f1 = RSurf_FogVertex(v);
6167                         f2 = 1 - f1;
6168                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6169                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6170                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6171                 }
6172         }
6173         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6174         R_Mesh_ResetTextureState();
6175         R_SetupShader_Generic_NoTexture(false, false);
6176         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6177 }
6178
6179 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6180 {
6181         // hacky overloading of the parameters
6182         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6183         int i;
6184         float color[4];
6185         prvm_edict_t *edict;
6186
6187         GL_CullFace(GL_NONE);
6188         R_SetupShader_Generic_NoTexture(false, false);
6189
6190         for (i = 0;i < numsurfaces;i++)
6191         {
6192                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6193                 switch ((int)PRVM_serveredictfloat(edict, solid))
6194                 {
6195                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6196                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6197                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6198                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6199                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6200                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6201                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6202                 }
6203                 if (prog == CLVM_prog)
6204                         color[3] *= r_showbboxes_client.value;
6205                 else
6206                         color[3] *= r_showbboxes.value;
6207                 color[3] = bound(0, color[3], 1);
6208                 GL_DepthTest(!r_showdisabledepthtest.integer);
6209                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6210         }
6211 }
6212
6213 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6214 {
6215         int i;
6216         prvm_edict_t *edict;
6217         vec3_t center;
6218
6219         if (prog == NULL)
6220                 return;
6221
6222         for (i = 0; i < prog->num_edicts; i++)
6223         {
6224                 edict = PRVM_EDICT_NUM(i);
6225                 if (edict->priv.server->free)
6226                         continue;
6227                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6228                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6229                         continue;
6230                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6231                         continue;
6232                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6233                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6234         }
6235 }
6236
6237 static const int nomodelelement3i[24] =
6238 {
6239         5, 2, 0,
6240         5, 1, 2,
6241         5, 0, 3,
6242         5, 3, 1,
6243         0, 2, 4,
6244         2, 1, 4,
6245         3, 0, 4,
6246         1, 3, 4
6247 };
6248
6249 static const unsigned short nomodelelement3s[24] =
6250 {
6251         5, 2, 0,
6252         5, 1, 2,
6253         5, 0, 3,
6254         5, 3, 1,
6255         0, 2, 4,
6256         2, 1, 4,
6257         3, 0, 4,
6258         1, 3, 4
6259 };
6260
6261 static const float nomodelvertex3f[6*3] =
6262 {
6263         -16,   0,   0,
6264          16,   0,   0,
6265           0, -16,   0,
6266           0,  16,   0,
6267           0,   0, -16,
6268           0,   0,  16
6269 };
6270
6271 static const float nomodelcolor4f[6*4] =
6272 {
6273         0.0f, 0.0f, 0.5f, 1.0f,
6274         0.0f, 0.0f, 0.5f, 1.0f,
6275         0.0f, 0.5f, 0.0f, 1.0f,
6276         0.0f, 0.5f, 0.0f, 1.0f,
6277         0.5f, 0.0f, 0.0f, 1.0f,
6278         0.5f, 0.0f, 0.0f, 1.0f
6279 };
6280
6281 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6282 {
6283         int i;
6284         float f1, f2, *c;
6285         float color4f[6*4];
6286
6287         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);
6288
6289         // this is only called once per entity so numsurfaces is always 1, and
6290         // surfacelist is always {0}, so this code does not handle batches
6291
6292         if (rsurface.ent_flags & RENDER_ADDITIVE)
6293         {
6294                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6295                 GL_DepthMask(false);
6296         }
6297         else if (ent->alpha < 1)
6298         {
6299                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6300                 GL_DepthMask(false);
6301         }
6302         else
6303         {
6304                 GL_BlendFunc(GL_ONE, GL_ZERO);
6305                 GL_DepthMask(true);
6306         }
6307         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6308         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6309         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6310         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6311         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6312         for (i = 0, c = color4f;i < 6;i++, c += 4)
6313         {
6314                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6315                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6316                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6317                 c[3] *= ent->alpha;
6318         }
6319         if (r_refdef.fogenabled)
6320         {
6321                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6322                 {
6323                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6324                         f2 = 1 - f1;
6325                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6326                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6327                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6328                 }
6329         }
6330 //      R_Mesh_ResetTextureState();
6331         R_SetupShader_Generic_NoTexture(false, false);
6332         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6333         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6334 }
6335
6336 void R_DrawNoModel(entity_render_t *ent)
6337 {
6338         vec3_t org;
6339         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6340         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6341                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6342         else
6343                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6344 }
6345
6346 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6347 {
6348         vec3_t right1, right2, diff, normal;
6349
6350         VectorSubtract (org2, org1, normal);
6351
6352         // calculate 'right' vector for start
6353         VectorSubtract (r_refdef.view.origin, org1, diff);
6354         CrossProduct (normal, diff, right1);
6355         VectorNormalize (right1);
6356
6357         // calculate 'right' vector for end
6358         VectorSubtract (r_refdef.view.origin, org2, diff);
6359         CrossProduct (normal, diff, right2);
6360         VectorNormalize (right2);
6361
6362         vert[ 0] = org1[0] + width * right1[0];
6363         vert[ 1] = org1[1] + width * right1[1];
6364         vert[ 2] = org1[2] + width * right1[2];
6365         vert[ 3] = org1[0] - width * right1[0];
6366         vert[ 4] = org1[1] - width * right1[1];
6367         vert[ 5] = org1[2] - width * right1[2];
6368         vert[ 6] = org2[0] - width * right2[0];
6369         vert[ 7] = org2[1] - width * right2[1];
6370         vert[ 8] = org2[2] - width * right2[2];
6371         vert[ 9] = org2[0] + width * right2[0];
6372         vert[10] = org2[1] + width * right2[1];
6373         vert[11] = org2[2] + width * right2[2];
6374 }
6375
6376 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)
6377 {
6378         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6379         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6380         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6381         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6382         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6383         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6384         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6385         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6386         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6387         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6388         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6389         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6390 }
6391
6392 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6393 {
6394         int i;
6395         float *vertex3f;
6396         float v[3];
6397         VectorSet(v, x, y, z);
6398         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6399                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6400                         break;
6401         if (i == mesh->numvertices)
6402         {
6403                 if (mesh->numvertices < mesh->maxvertices)
6404                 {
6405                         VectorCopy(v, vertex3f);
6406                         mesh->numvertices++;
6407                 }
6408                 return mesh->numvertices;
6409         }
6410         else
6411                 return i;
6412 }
6413
6414 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6415 {
6416         int i;
6417         int *e, element[3];
6418         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6419         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6420         e = mesh->element3i + mesh->numtriangles * 3;
6421         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6422         {
6423                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6424                 if (mesh->numtriangles < mesh->maxtriangles)
6425                 {
6426                         *e++ = element[0];
6427                         *e++ = element[1];
6428                         *e++ = element[2];
6429                         mesh->numtriangles++;
6430                 }
6431                 element[1] = element[2];
6432         }
6433 }
6434
6435 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6436 {
6437         int i;
6438         int *e, element[3];
6439         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6440         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6441         e = mesh->element3i + mesh->numtriangles * 3;
6442         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6443         {
6444                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6445                 if (mesh->numtriangles < mesh->maxtriangles)
6446                 {
6447                         *e++ = element[0];
6448                         *e++ = element[1];
6449                         *e++ = element[2];
6450                         mesh->numtriangles++;
6451                 }
6452                 element[1] = element[2];
6453         }
6454 }
6455
6456 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6457 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6458 {
6459         int planenum, planenum2;
6460         int w;
6461         int tempnumpoints;
6462         mplane_t *plane, *plane2;
6463         double maxdist;
6464         double temppoints[2][256*3];
6465         // figure out how large a bounding box we need to properly compute this brush
6466         maxdist = 0;
6467         for (w = 0;w < numplanes;w++)
6468                 maxdist = max(maxdist, fabs(planes[w].dist));
6469         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6470         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6471         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6472         {
6473                 w = 0;
6474                 tempnumpoints = 4;
6475                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6476                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6477                 {
6478                         if (planenum2 == planenum)
6479                                 continue;
6480                         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);
6481                         w = !w;
6482                 }
6483                 if (tempnumpoints < 3)
6484                         continue;
6485                 // generate elements forming a triangle fan for this polygon
6486                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6487         }
6488 }
6489
6490 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6491 {
6492         if(parms[0] == 0 && parms[1] == 0)
6493                 return false;
6494         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6495                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6496                         return false;
6497         return true;
6498 }
6499
6500 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6501 {
6502         double index, f;
6503         index = parms[2] + rsurface.shadertime * parms[3];
6504         index -= floor(index);
6505         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6506         {
6507         default:
6508         case Q3WAVEFUNC_NONE:
6509         case Q3WAVEFUNC_NOISE:
6510         case Q3WAVEFUNC_COUNT:
6511                 f = 0;
6512                 break;
6513         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6514         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6515         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6516         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6517         case Q3WAVEFUNC_TRIANGLE:
6518                 index *= 4;
6519                 f = index - floor(index);
6520                 if (index < 1)
6521                 {
6522                         // f = f;
6523                 }
6524                 else if (index < 2)
6525                         f = 1 - f;
6526                 else if (index < 3)
6527                         f = -f;
6528                 else
6529                         f = -(1 - f);
6530                 break;
6531         }
6532         f = parms[0] + parms[1] * f;
6533         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6534                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6535         return (float) f;
6536 }
6537
6538 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6539 {
6540         int w, h, idx;
6541         float shadertime;
6542         float f;
6543         float offsetd[2];
6544         float tcmat[12];
6545         matrix4x4_t matrix, temp;
6546         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6547         // it's better to have one huge fixup every 9 hours than gradual
6548         // degradation over time which looks consistently bad after many hours.
6549         //
6550         // tcmod scroll in particular suffers from this degradation which can't be
6551         // effectively worked around even with floor() tricks because we don't
6552         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6553         // a workaround involving floor() would be incorrect anyway...
6554         shadertime = rsurface.shadertime;
6555         if (shadertime >= 32768.0f)
6556                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6557         switch(tcmod->tcmod)
6558         {
6559                 case Q3TCMOD_COUNT:
6560                 case Q3TCMOD_NONE:
6561                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6562                                 matrix = r_waterscrollmatrix;
6563                         else
6564                                 matrix = identitymatrix;
6565                         break;
6566                 case Q3TCMOD_ENTITYTRANSLATE:
6567                         // this is used in Q3 to allow the gamecode to control texcoord
6568                         // scrolling on the entity, which is not supported in darkplaces yet.
6569                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6570                         break;
6571                 case Q3TCMOD_ROTATE:
6572                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6573                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6574                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6575                         break;
6576                 case Q3TCMOD_SCALE:
6577                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6578                         break;
6579                 case Q3TCMOD_SCROLL:
6580                         // this particular tcmod is a "bug for bug" compatible one with regards to
6581                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6582                         // specifically did the wrapping and so we must mimic that...
6583                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6584                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6585                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6586                         break;
6587                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6588                         w = (int) tcmod->parms[0];
6589                         h = (int) tcmod->parms[1];
6590                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6591                         f = f - floor(f);
6592                         idx = (int) floor(f * w * h);
6593                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6594                         break;
6595                 case Q3TCMOD_STRETCH:
6596                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6597                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6598                         break;
6599                 case Q3TCMOD_TRANSFORM:
6600                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6601                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6602                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6603                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6604                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6605                         break;
6606                 case Q3TCMOD_TURBULENT:
6607                         // this is handled in the RSurf_PrepareVertices function
6608                         matrix = identitymatrix;
6609                         break;
6610         }
6611         temp = *texmatrix;
6612         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6613 }
6614
6615 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6616 {
6617         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6618         char name[MAX_QPATH];
6619         skinframe_t *skinframe;
6620         unsigned char pixels[296*194];
6621         strlcpy(cache->name, skinname, sizeof(cache->name));
6622         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6623         if (developer_loading.integer)
6624                 Con_Printf("loading %s\n", name);
6625         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6626         if (!skinframe || !skinframe->base)
6627         {
6628                 unsigned char *f;
6629                 fs_offset_t filesize;
6630                 skinframe = NULL;
6631                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6632                 if (f)
6633                 {
6634                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6635                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6636                         Mem_Free(f);
6637                 }
6638         }
6639         cache->skinframe = skinframe;
6640 }
6641
6642 texture_t *R_GetCurrentTexture(texture_t *t)
6643 {
6644         int i, q;
6645         const entity_render_t *ent = rsurface.entity;
6646         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6647         q3shaderinfo_layer_tcmod_t *tcmod;
6648         float specularscale = 0.0f;
6649
6650         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6651                 return t->currentframe;
6652         t->update_lastrenderframe = r_textureframe;
6653         t->update_lastrenderentity = (void *)ent;
6654
6655         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6656                 t->camera_entity = ent->entitynumber;
6657         else
6658                 t->camera_entity = 0;
6659
6660         // switch to an alternate material if this is a q1bsp animated material
6661         {
6662                 texture_t *texture = t;
6663                 int s = rsurface.ent_skinnum;
6664                 if ((unsigned int)s >= (unsigned int)model->numskins)
6665                         s = 0;
6666                 if (model->skinscenes)
6667                 {
6668                         if (model->skinscenes[s].framecount > 1)
6669                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6670                         else
6671                                 s = model->skinscenes[s].firstframe;
6672                 }
6673                 if (s > 0)
6674                         t = t + s * model->num_surfaces;
6675                 if (t->animated)
6676                 {
6677                         // use an alternate animation if the entity's frame is not 0,
6678                         // and only if the texture has an alternate animation
6679                         if (t->animated == 2) // q2bsp
6680                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6681                         else if (rsurface.ent_alttextures && t->anim_total[1])
6682                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6683                         else
6684                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6685                 }
6686                 texture->currentframe = t;
6687         }
6688
6689         // update currentskinframe to be a qw skin or animation frame
6690         if (rsurface.ent_qwskin >= 0)
6691         {
6692                 i = rsurface.ent_qwskin;
6693                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6694                 {
6695                         r_qwskincache_size = cl.maxclients;
6696                         if (r_qwskincache)
6697                                 Mem_Free(r_qwskincache);
6698                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6699                 }
6700                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6701                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6702                 t->currentskinframe = r_qwskincache[i].skinframe;
6703                 if (t->materialshaderpass && t->currentskinframe == NULL)
6704                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6705         }
6706         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6707                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6708         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6709                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6710
6711         t->currentmaterialflags = t->basematerialflags;
6712         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6713         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6714                 t->currentalpha *= r_wateralpha.value;
6715         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6716                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6717         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6718                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6719
6720         // decide on which type of lighting to use for this surface
6721         if (rsurface.entity->render_modellight_forced)
6722                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6723         if (rsurface.entity->render_rtlight_disabled)
6724                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6725         if (rsurface.entity->render_lightgrid)
6726                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6727         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6728         {
6729                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6730                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6731                 for (q = 0; q < 3; q++)
6732                 {
6733                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6734                         t->render_modellight_lightdir[q] = q == 2;
6735                         t->render_modellight_ambient[q] = 1;
6736                         t->render_modellight_diffuse[q] = 0;
6737                         t->render_modellight_specular[q] = 0;
6738                         t->render_lightmap_ambient[q] = 0;
6739                         t->render_lightmap_diffuse[q] = 0;
6740                         t->render_lightmap_specular[q] = 0;
6741                         t->render_rtlight_diffuse[q] = 0;
6742                         t->render_rtlight_specular[q] = 0;
6743                 }
6744         }
6745         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6746         {
6747                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6748                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6749                 for (q = 0; q < 3; q++)
6750                 {
6751                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6752                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6753                         t->render_modellight_lightdir[q] = q == 2;
6754                         t->render_modellight_diffuse[q] = 0;
6755                         t->render_modellight_specular[q] = 0;
6756                         t->render_lightmap_ambient[q] = 0;
6757                         t->render_lightmap_diffuse[q] = 0;
6758                         t->render_lightmap_specular[q] = 0;
6759                         t->render_rtlight_diffuse[q] = 0;
6760                         t->render_rtlight_specular[q] = 0;
6761                 }
6762         }
6763         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6764         {
6765                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6766                 for (q = 0; q < 3; q++)
6767                 {
6768                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6769                         t->render_modellight_lightdir[q] = q == 2;
6770                         t->render_modellight_ambient[q] = 0;
6771                         t->render_modellight_diffuse[q] = 0;
6772                         t->render_modellight_specular[q] = 0;
6773                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6774                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6775                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6776                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6777                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6778                 }
6779         }
6780         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6781         {
6782                 // ambient + single direction light (modellight)
6783                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6784                 for (q = 0; q < 3; q++)
6785                 {
6786                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6787                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6788                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6789                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6790                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6791                         t->render_lightmap_ambient[q] = 0;
6792                         t->render_lightmap_diffuse[q] = 0;
6793                         t->render_lightmap_specular[q] = 0;
6794                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6795                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6796                 }
6797         }
6798         else
6799         {
6800                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6801                 for (q = 0; q < 3; q++)
6802                 {
6803                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6804                         t->render_modellight_lightdir[q] = q == 2;
6805                         t->render_modellight_ambient[q] = 0;
6806                         t->render_modellight_diffuse[q] = 0;
6807                         t->render_modellight_specular[q] = 0;
6808                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6809                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6810                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6811                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6812                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6813                 }
6814         }
6815
6816         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6817         {
6818                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6819                 // attribute, we punt it to the lightmap path and hope for the best,
6820                 // but lighting doesn't work.
6821                 //
6822                 // FIXME: this is fine for effects but CSQC polygons should be subject
6823                 // to lighting.
6824                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6825                 for (q = 0; q < 3; q++)
6826                 {
6827                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6828                         t->render_modellight_lightdir[q] = q == 2;
6829                         t->render_modellight_ambient[q] = 0;
6830                         t->render_modellight_diffuse[q] = 0;
6831                         t->render_modellight_specular[q] = 0;
6832                         t->render_lightmap_ambient[q] = 0;
6833                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6834                         t->render_lightmap_specular[q] = 0;
6835                         t->render_rtlight_diffuse[q] = 0;
6836                         t->render_rtlight_specular[q] = 0;
6837                 }
6838         }
6839
6840         for (q = 0; q < 3; q++)
6841         {
6842                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6843                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6844         }
6845
6846         if (rsurface.ent_flags & RENDER_ADDITIVE)
6847                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6848         else if (t->currentalpha < 1)
6849                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6850         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6851         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6852                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6853         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6854                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6855         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6856                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6857         if (t->backgroundshaderpass)
6858                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6859         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6860         {
6861                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6862                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6863         }
6864         else
6865                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6866         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6867         {
6868                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6869                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6870         }
6871         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6872                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6873
6874         // there is no tcmod
6875         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6876         {
6877                 t->currenttexmatrix = r_waterscrollmatrix;
6878                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6879         }
6880         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6881         {
6882                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6883                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6884         }
6885
6886         if (t->materialshaderpass)
6887                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6888                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6889
6890         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6891         if (t->currentskinframe->qpixels)
6892                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6893         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6894         if (!t->basetexture)
6895                 t->basetexture = r_texture_notexture;
6896         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6897         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6898         t->nmaptexture = t->currentskinframe->nmap;
6899         if (!t->nmaptexture)
6900                 t->nmaptexture = r_texture_blanknormalmap;
6901         t->glosstexture = r_texture_black;
6902         t->glowtexture = t->currentskinframe->glow;
6903         t->fogtexture = t->currentskinframe->fog;
6904         t->reflectmasktexture = t->currentskinframe->reflect;
6905         if (t->backgroundshaderpass)
6906         {
6907                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6908                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6909                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6910                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6911                 t->backgroundglosstexture = r_texture_black;
6912                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6913                 if (!t->backgroundnmaptexture)
6914                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6915                 // make sure that if glow is going to be used, both textures are not NULL
6916                 if (!t->backgroundglowtexture && t->glowtexture)
6917                         t->backgroundglowtexture = r_texture_black;
6918                 if (!t->glowtexture && t->backgroundglowtexture)
6919                         t->glowtexture = r_texture_black;
6920         }
6921         else
6922         {
6923                 t->backgroundbasetexture = r_texture_white;
6924                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6925                 t->backgroundglosstexture = r_texture_black;
6926                 t->backgroundglowtexture = NULL;
6927         }
6928         t->specularpower = r_shadow_glossexponent.value;
6929         // TODO: store reference values for these in the texture?
6930         if (r_shadow_gloss.integer > 0)
6931         {
6932                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6933                 {
6934                         if (r_shadow_glossintensity.value > 0)
6935                         {
6936                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6937                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6938                                 specularscale = r_shadow_glossintensity.value;
6939                         }
6940                 }
6941                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6942                 {
6943                         t->glosstexture = r_texture_white;
6944                         t->backgroundglosstexture = r_texture_white;
6945                         specularscale = r_shadow_gloss2intensity.value;
6946                         t->specularpower = r_shadow_gloss2exponent.value;
6947                 }
6948         }
6949         specularscale *= t->specularscalemod;
6950         t->specularpower *= t->specularpowermod;
6951
6952         // lightmaps mode looks bad with dlights using actual texturing, so turn
6953         // off the colormap and glossmap, but leave the normalmap on as it still
6954         // accurately represents the shading involved
6955         if (gl_lightmaps.integer)
6956         {
6957                 t->basetexture = r_texture_grey128;
6958                 t->pantstexture = r_texture_black;
6959                 t->shirttexture = r_texture_black;
6960                 if (gl_lightmaps.integer < 2)
6961                         t->nmaptexture = r_texture_blanknormalmap;
6962                 t->glosstexture = r_texture_black;
6963                 t->glowtexture = NULL;
6964                 t->fogtexture = NULL;
6965                 t->reflectmasktexture = NULL;
6966                 t->backgroundbasetexture = NULL;
6967                 if (gl_lightmaps.integer < 2)
6968                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6969                 t->backgroundglosstexture = r_texture_black;
6970                 t->backgroundglowtexture = NULL;
6971                 specularscale = 0;
6972                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6973         }
6974
6975         if (specularscale != 1.0f)
6976         {
6977                 for (q = 0; q < 3; q++)
6978                 {
6979                         t->render_modellight_specular[q] *= specularscale;
6980                         t->render_lightmap_specular[q] *= specularscale;
6981                         t->render_rtlight_specular[q] *= specularscale;
6982                 }
6983         }
6984
6985         t->currentblendfunc[0] = GL_ONE;
6986         t->currentblendfunc[1] = GL_ZERO;
6987         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6988         {
6989                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6990                 t->currentblendfunc[1] = GL_ONE;
6991         }
6992         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6993         {
6994                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6995                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6996         }
6997         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6998         {
6999                 t->currentblendfunc[0] = t->customblendfunc[0];
7000                 t->currentblendfunc[1] = t->customblendfunc[1];
7001         }
7002
7003         return t;
7004 }
7005
7006 rsurfacestate_t rsurface;
7007
7008 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7009 {
7010         dp_model_t *model = ent->model;
7011         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7012         //      return;
7013         rsurface.entity = (entity_render_t *)ent;
7014         rsurface.skeleton = ent->skeleton;
7015         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7016         rsurface.ent_skinnum = ent->skinnum;
7017         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;
7018         rsurface.ent_flags = ent->flags;
7019         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7020                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7021         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7022         rsurface.matrix = ent->matrix;
7023         rsurface.inversematrix = ent->inversematrix;
7024         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7025         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7026         R_EntityMatrix(&rsurface.matrix);
7027         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7028         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7029         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7030         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7031         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7032         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7033         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7034         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7035         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7036         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7037         if (ent->model->brush.submodel && !prepass)
7038         {
7039                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7040                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7041         }
7042         // if the animcache code decided it should use the shader path, skip the deform step
7043         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7044         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7045         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7046         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7047         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7048         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7049         {
7050                 if (ent->animcache_vertex3f)
7051                 {
7052                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7053                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7054                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7055                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7056                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7057                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7058                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7059                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7060                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7061                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7062                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7063                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7064                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7065                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7066                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7067                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7068                 }
7069                 else if (wanttangents)
7070                 {
7071                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7072                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7073                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7074                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7075                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7076                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7077                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7078                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7079                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7080                         rsurface.modelvertex3f_vertexbuffer = NULL;
7081                         rsurface.modelvertex3f_bufferoffset = 0;
7082                         rsurface.modelvertex3f_vertexbuffer = 0;
7083                         rsurface.modelvertex3f_bufferoffset = 0;
7084                         rsurface.modelsvector3f_vertexbuffer = 0;
7085                         rsurface.modelsvector3f_bufferoffset = 0;
7086                         rsurface.modeltvector3f_vertexbuffer = 0;
7087                         rsurface.modeltvector3f_bufferoffset = 0;
7088                         rsurface.modelnormal3f_vertexbuffer = 0;
7089                         rsurface.modelnormal3f_bufferoffset = 0;
7090                 }
7091                 else if (wantnormals)
7092                 {
7093                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7094                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7095                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7096                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7097                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7098                         rsurface.modelsvector3f = NULL;
7099                         rsurface.modeltvector3f = NULL;
7100                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7101                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7102                         rsurface.modelvertex3f_vertexbuffer = NULL;
7103                         rsurface.modelvertex3f_bufferoffset = 0;
7104                         rsurface.modelvertex3f_vertexbuffer = 0;
7105                         rsurface.modelvertex3f_bufferoffset = 0;
7106                         rsurface.modelsvector3f_vertexbuffer = 0;
7107                         rsurface.modelsvector3f_bufferoffset = 0;
7108                         rsurface.modeltvector3f_vertexbuffer = 0;
7109                         rsurface.modeltvector3f_bufferoffset = 0;
7110                         rsurface.modelnormal3f_vertexbuffer = 0;
7111                         rsurface.modelnormal3f_bufferoffset = 0;
7112                 }
7113                 else
7114                 {
7115                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7116                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7117                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7118                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7119                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7120                         rsurface.modelsvector3f = NULL;
7121                         rsurface.modeltvector3f = NULL;
7122                         rsurface.modelnormal3f = NULL;
7123                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7124                         rsurface.modelvertex3f_vertexbuffer = NULL;
7125                         rsurface.modelvertex3f_bufferoffset = 0;
7126                         rsurface.modelvertex3f_vertexbuffer = 0;
7127                         rsurface.modelvertex3f_bufferoffset = 0;
7128                         rsurface.modelsvector3f_vertexbuffer = 0;
7129                         rsurface.modelsvector3f_bufferoffset = 0;
7130                         rsurface.modeltvector3f_vertexbuffer = 0;
7131                         rsurface.modeltvector3f_bufferoffset = 0;
7132                         rsurface.modelnormal3f_vertexbuffer = 0;
7133                         rsurface.modelnormal3f_bufferoffset = 0;
7134                 }
7135                 rsurface.modelgeneratedvertex = true;
7136         }
7137         else
7138         {
7139                 if (rsurface.entityskeletaltransform3x4)
7140                 {
7141                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7142                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7143                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7144                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7145                 }
7146                 else
7147                 {
7148                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7149                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7150                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7151                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7152                 }
7153                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7154                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7155                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7156                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7157                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7158                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7159                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7160                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7161                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7162                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7163                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7164                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7165                 rsurface.modelgeneratedvertex = false;
7166         }
7167         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7168         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7169         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7170         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7171         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7172         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7173         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7174         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7175         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7176         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7177         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7178         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7179         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7180         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7181         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7182         rsurface.modelelement3i = model->surfmesh.data_element3i;
7183         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7184         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7185         rsurface.modelelement3s = model->surfmesh.data_element3s;
7186         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7187         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7188         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7189         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7190         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7191         rsurface.modelsurfaces = model->data_surfaces;
7192         rsurface.batchgeneratedvertex = false;
7193         rsurface.batchfirstvertex = 0;
7194         rsurface.batchnumvertices = 0;
7195         rsurface.batchfirsttriangle = 0;
7196         rsurface.batchnumtriangles = 0;
7197         rsurface.batchvertex3f  = NULL;
7198         rsurface.batchvertex3f_vertexbuffer = NULL;
7199         rsurface.batchvertex3f_bufferoffset = 0;
7200         rsurface.batchsvector3f = NULL;
7201         rsurface.batchsvector3f_vertexbuffer = NULL;
7202         rsurface.batchsvector3f_bufferoffset = 0;
7203         rsurface.batchtvector3f = NULL;
7204         rsurface.batchtvector3f_vertexbuffer = NULL;
7205         rsurface.batchtvector3f_bufferoffset = 0;
7206         rsurface.batchnormal3f  = NULL;
7207         rsurface.batchnormal3f_vertexbuffer = NULL;
7208         rsurface.batchnormal3f_bufferoffset = 0;
7209         rsurface.batchlightmapcolor4f = NULL;
7210         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7211         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7212         rsurface.batchtexcoordtexture2f = NULL;
7213         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7214         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7215         rsurface.batchtexcoordlightmap2f = NULL;
7216         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7217         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7218         rsurface.batchskeletalindex4ub = NULL;
7219         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7220         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7221         rsurface.batchskeletalweight4ub = NULL;
7222         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7223         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7224         rsurface.batchelement3i = NULL;
7225         rsurface.batchelement3i_indexbuffer = NULL;
7226         rsurface.batchelement3i_bufferoffset = 0;
7227         rsurface.batchelement3s = NULL;
7228         rsurface.batchelement3s_indexbuffer = NULL;
7229         rsurface.batchelement3s_bufferoffset = 0;
7230         rsurface.forcecurrenttextureupdate = false;
7231 }
7232
7233 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
7234 {
7235         rsurface.entity = r_refdef.scene.worldentity;
7236         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7237                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7238                 // A better approach could be making this copy only once per frame.
7239                 static entity_render_t custom_entity;
7240                 int q;
7241                 custom_entity = *rsurface.entity;
7242                 for (q = 0; q < 3; ++q) {
7243                         float colormod = q == 0 ? r : q == 1 ? g : b;
7244                         custom_entity.render_fullbright[q] *= colormod;
7245                         custom_entity.render_modellight_ambient[q] *= colormod;
7246                         custom_entity.render_modellight_diffuse[q] *= colormod;
7247                         custom_entity.render_lightmap_ambient[q] *= colormod;
7248                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7249                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7250                 }
7251                 custom_entity.alpha *= a;
7252                 rsurface.entity = &custom_entity;
7253         }
7254         rsurface.skeleton = NULL;
7255         rsurface.ent_skinnum = 0;
7256         rsurface.ent_qwskin = -1;
7257         rsurface.ent_flags = entflags;
7258         rsurface.shadertime = r_refdef.scene.time - shadertime;
7259         rsurface.modelnumvertices = numvertices;
7260         rsurface.modelnumtriangles = numtriangles;
7261         rsurface.matrix = *matrix;
7262         rsurface.inversematrix = *inversematrix;
7263         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7264         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7265         R_EntityMatrix(&rsurface.matrix);
7266         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7267         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7268         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7269         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7270         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7271         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7272         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7273         rsurface.frameblend[0].lerp = 1;
7274         rsurface.ent_alttextures = false;
7275         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7276         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7277         rsurface.entityskeletaltransform3x4 = NULL;
7278         rsurface.entityskeletaltransform3x4buffer = NULL;
7279         rsurface.entityskeletaltransform3x4offset = 0;
7280         rsurface.entityskeletaltransform3x4size = 0;
7281         rsurface.entityskeletalnumtransforms = 0;
7282         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7283         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7284         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7285         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7286         if (wanttangents)
7287         {
7288                 rsurface.modelvertex3f = (float *)vertex3f;
7289                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7290                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7291                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7292         }
7293         else if (wantnormals)
7294         {
7295                 rsurface.modelvertex3f = (float *)vertex3f;
7296                 rsurface.modelsvector3f = NULL;
7297                 rsurface.modeltvector3f = NULL;
7298                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7299         }
7300         else
7301         {
7302                 rsurface.modelvertex3f = (float *)vertex3f;
7303                 rsurface.modelsvector3f = NULL;
7304                 rsurface.modeltvector3f = NULL;
7305                 rsurface.modelnormal3f = NULL;
7306         }
7307         rsurface.modelvertex3f_vertexbuffer = 0;
7308         rsurface.modelvertex3f_bufferoffset = 0;
7309         rsurface.modelsvector3f_vertexbuffer = 0;
7310         rsurface.modelsvector3f_bufferoffset = 0;
7311         rsurface.modeltvector3f_vertexbuffer = 0;
7312         rsurface.modeltvector3f_bufferoffset = 0;
7313         rsurface.modelnormal3f_vertexbuffer = 0;
7314         rsurface.modelnormal3f_bufferoffset = 0;
7315         rsurface.modelgeneratedvertex = true;
7316         rsurface.modellightmapcolor4f  = (float *)color4f;
7317         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7318         rsurface.modellightmapcolor4f_bufferoffset = 0;
7319         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7320         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7321         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7322         rsurface.modeltexcoordlightmap2f  = NULL;
7323         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7324         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7325         rsurface.modelskeletalindex4ub = NULL;
7326         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7327         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7328         rsurface.modelskeletalweight4ub = NULL;
7329         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7330         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7331         rsurface.modelelement3i = (int *)element3i;
7332         rsurface.modelelement3i_indexbuffer = NULL;
7333         rsurface.modelelement3i_bufferoffset = 0;
7334         rsurface.modelelement3s = (unsigned short *)element3s;
7335         rsurface.modelelement3s_indexbuffer = NULL;
7336         rsurface.modelelement3s_bufferoffset = 0;
7337         rsurface.modellightmapoffsets = NULL;
7338         rsurface.modelsurfaces = NULL;
7339         rsurface.batchgeneratedvertex = false;
7340         rsurface.batchfirstvertex = 0;
7341         rsurface.batchnumvertices = 0;
7342         rsurface.batchfirsttriangle = 0;
7343         rsurface.batchnumtriangles = 0;
7344         rsurface.batchvertex3f  = NULL;
7345         rsurface.batchvertex3f_vertexbuffer = NULL;
7346         rsurface.batchvertex3f_bufferoffset = 0;
7347         rsurface.batchsvector3f = NULL;
7348         rsurface.batchsvector3f_vertexbuffer = NULL;
7349         rsurface.batchsvector3f_bufferoffset = 0;
7350         rsurface.batchtvector3f = NULL;
7351         rsurface.batchtvector3f_vertexbuffer = NULL;
7352         rsurface.batchtvector3f_bufferoffset = 0;
7353         rsurface.batchnormal3f  = NULL;
7354         rsurface.batchnormal3f_vertexbuffer = NULL;
7355         rsurface.batchnormal3f_bufferoffset = 0;
7356         rsurface.batchlightmapcolor4f = NULL;
7357         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7358         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7359         rsurface.batchtexcoordtexture2f = NULL;
7360         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7361         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7362         rsurface.batchtexcoordlightmap2f = NULL;
7363         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7364         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7365         rsurface.batchskeletalindex4ub = NULL;
7366         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7367         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7368         rsurface.batchskeletalweight4ub = NULL;
7369         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7370         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7371         rsurface.batchelement3i = NULL;
7372         rsurface.batchelement3i_indexbuffer = NULL;
7373         rsurface.batchelement3i_bufferoffset = 0;
7374         rsurface.batchelement3s = NULL;
7375         rsurface.batchelement3s_indexbuffer = NULL;
7376         rsurface.batchelement3s_bufferoffset = 0;
7377         rsurface.forcecurrenttextureupdate = true;
7378
7379         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7380         {
7381                 if ((wantnormals || wanttangents) && !normal3f)
7382                 {
7383                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7384                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7385                 }
7386                 if (wanttangents && !svector3f)
7387                 {
7388                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7389                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7390                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7391                 }
7392         }
7393 }
7394
7395 float RSurf_FogPoint(const float *v)
7396 {
7397         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7398         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7399         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7400         float FogHeightFade = r_refdef.fogheightfade;
7401         float fogfrac;
7402         unsigned int fogmasktableindex;
7403         if (r_refdef.fogplaneviewabove)
7404                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7405         else
7406                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7407         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7408         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7409 }
7410
7411 float RSurf_FogVertex(const float *v)
7412 {
7413         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7414         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7415         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7416         float FogHeightFade = rsurface.fogheightfade;
7417         float fogfrac;
7418         unsigned int fogmasktableindex;
7419         if (r_refdef.fogplaneviewabove)
7420                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7421         else
7422                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7423         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7424         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7425 }
7426
7427 void RSurf_UploadBuffersForBatch(void)
7428 {
7429         // 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)
7430         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7431         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7432                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7433         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7434                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7435         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7436                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7437         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7438                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7439         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7440                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7441         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7442                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7443         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7444                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7445         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7446                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7447         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7448                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7449
7450         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7451                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7452         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7453                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7454
7455         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7456         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7457         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7458         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7459         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7460         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7461         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7462         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7463         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7464         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7465 }
7466
7467 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7468 {
7469         int i;
7470         for (i = 0;i < numelements;i++)
7471                 outelement3i[i] = inelement3i[i] + adjust;
7472 }
7473
7474 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7475 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7476 {
7477         int deformindex;
7478         int firsttriangle;
7479         int numtriangles;
7480         int firstvertex;
7481         int endvertex;
7482         int numvertices;
7483         int surfacefirsttriangle;
7484         int surfacenumtriangles;
7485         int surfacefirstvertex;
7486         int surfaceendvertex;
7487         int surfacenumvertices;
7488         int batchnumsurfaces = texturenumsurfaces;
7489         int batchnumvertices;
7490         int batchnumtriangles;
7491         int i, j;
7492         qboolean gaps;
7493         qboolean dynamicvertex;
7494         float amplitude;
7495         float animpos;
7496         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7497         float waveparms[4];
7498         unsigned char *ub;
7499         q3shaderinfo_deform_t *deform;
7500         const msurface_t *surface, *firstsurface;
7501         if (!texturenumsurfaces)
7502                 return;
7503         // find vertex range of this surface batch
7504         gaps = false;
7505         firstsurface = texturesurfacelist[0];
7506         firsttriangle = firstsurface->num_firsttriangle;
7507         batchnumvertices = 0;
7508         batchnumtriangles = 0;
7509         firstvertex = endvertex = firstsurface->num_firstvertex;
7510         for (i = 0;i < texturenumsurfaces;i++)
7511         {
7512                 surface = texturesurfacelist[i];
7513                 if (surface != firstsurface + i)
7514                         gaps = true;
7515                 surfacefirstvertex = surface->num_firstvertex;
7516                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7517                 surfacenumvertices = surface->num_vertices;
7518                 surfacenumtriangles = surface->num_triangles;
7519                 if (firstvertex > surfacefirstvertex)
7520                         firstvertex = surfacefirstvertex;
7521                 if (endvertex < surfaceendvertex)
7522                         endvertex = surfaceendvertex;
7523                 batchnumvertices += surfacenumvertices;
7524                 batchnumtriangles += surfacenumtriangles;
7525         }
7526
7527         r_refdef.stats[r_stat_batch_batches]++;
7528         if (gaps)
7529                 r_refdef.stats[r_stat_batch_withgaps]++;
7530         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7531         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7532         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7533
7534         // we now know the vertex range used, and if there are any gaps in it
7535         rsurface.batchfirstvertex = firstvertex;
7536         rsurface.batchnumvertices = endvertex - firstvertex;
7537         rsurface.batchfirsttriangle = firsttriangle;
7538         rsurface.batchnumtriangles = batchnumtriangles;
7539
7540         // check if any dynamic vertex processing must occur
7541         dynamicvertex = false;
7542
7543         // we must use vertexbuffers for rendering, we can upload vertex buffers
7544         // easily enough but if the basevertex is non-zero it becomes more
7545         // difficult, so force dynamicvertex path in that case - it's suboptimal
7546         // but the most optimal case is to have the geometry sources provide their
7547         // own anyway.
7548         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7549                 dynamicvertex = true;
7550
7551         // a cvar to force the dynamic vertex path to be taken, for debugging
7552         if (r_batch_debugdynamicvertexpath.integer)
7553         {
7554                 if (!dynamicvertex)
7555                 {
7556                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7557                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7558                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7559                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7560                 }
7561                 dynamicvertex = true;
7562         }
7563
7564         // if there is a chance of animated vertex colors, it's a dynamic batch
7565         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7566         {
7567                 if (!dynamicvertex)
7568                 {
7569                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7570                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7571                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7572                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7573                 }
7574                 dynamicvertex = true;
7575         }
7576
7577         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7578         {
7579                 switch (deform->deform)
7580                 {
7581                 default:
7582                 case Q3DEFORM_PROJECTIONSHADOW:
7583                 case Q3DEFORM_TEXT0:
7584                 case Q3DEFORM_TEXT1:
7585                 case Q3DEFORM_TEXT2:
7586                 case Q3DEFORM_TEXT3:
7587                 case Q3DEFORM_TEXT4:
7588                 case Q3DEFORM_TEXT5:
7589                 case Q3DEFORM_TEXT6:
7590                 case Q3DEFORM_TEXT7:
7591                 case Q3DEFORM_NONE:
7592                         break;
7593                 case Q3DEFORM_AUTOSPRITE:
7594                         if (!dynamicvertex)
7595                         {
7596                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7597                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7598                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7599                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7600                         }
7601                         dynamicvertex = true;
7602                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7603                         break;
7604                 case Q3DEFORM_AUTOSPRITE2:
7605                         if (!dynamicvertex)
7606                         {
7607                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7608                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7609                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7610                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7611                         }
7612                         dynamicvertex = true;
7613                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7614                         break;
7615                 case Q3DEFORM_NORMAL:
7616                         if (!dynamicvertex)
7617                         {
7618                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7619                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7620                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7621                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7622                         }
7623                         dynamicvertex = true;
7624                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7625                         break;
7626                 case Q3DEFORM_WAVE:
7627                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7628                                 break; // if wavefunc is a nop, ignore this transform
7629                         if (!dynamicvertex)
7630                         {
7631                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7632                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7633                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7634                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7635                         }
7636                         dynamicvertex = true;
7637                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7638                         break;
7639                 case Q3DEFORM_BULGE:
7640                         if (!dynamicvertex)
7641                         {
7642                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7643                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7644                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7645                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7646                         }
7647                         dynamicvertex = true;
7648                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7649                         break;
7650                 case Q3DEFORM_MOVE:
7651                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7652                                 break; // if wavefunc is a nop, ignore this transform
7653                         if (!dynamicvertex)
7654                         {
7655                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7656                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7657                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7658                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7659                         }
7660                         dynamicvertex = true;
7661                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7662                         break;
7663                 }
7664         }
7665         if (rsurface.texture->materialshaderpass)
7666         {
7667                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7668                 {
7669                 default:
7670                 case Q3TCGEN_TEXTURE:
7671                         break;
7672                 case Q3TCGEN_LIGHTMAP:
7673                         if (!dynamicvertex)
7674                         {
7675                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7676                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7677                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7678                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7679                         }
7680                         dynamicvertex = true;
7681                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7682                         break;
7683                 case Q3TCGEN_VECTOR:
7684                         if (!dynamicvertex)
7685                         {
7686                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7687                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7688                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7689                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7690                         }
7691                         dynamicvertex = true;
7692                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7693                         break;
7694                 case Q3TCGEN_ENVIRONMENT:
7695                         if (!dynamicvertex)
7696                         {
7697                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7698                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7699                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7700                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7701                         }
7702                         dynamicvertex = true;
7703                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7704                         break;
7705                 }
7706                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7707                 {
7708                         if (!dynamicvertex)
7709                         {
7710                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7711                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7712                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7713                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7714                         }
7715                         dynamicvertex = true;
7716                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7717                 }
7718         }
7719
7720         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7721         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7722         // we ensure this by treating the vertex batch as dynamic...
7723         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7724         {
7725                 if (!dynamicvertex)
7726                 {
7727                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7728                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7729                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7730                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7731                 }
7732                 dynamicvertex = true;
7733         }
7734
7735         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7736         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7737                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7738
7739         rsurface.batchvertex3f = rsurface.modelvertex3f;
7740         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7741         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7742         rsurface.batchsvector3f = rsurface.modelsvector3f;
7743         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7744         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7745         rsurface.batchtvector3f = rsurface.modeltvector3f;
7746         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7747         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7748         rsurface.batchnormal3f = rsurface.modelnormal3f;
7749         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7750         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7751         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7752         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7753         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7754         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7755         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7756         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7757         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7758         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7759         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7760         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7761         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7762         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7763         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7764         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7765         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7766         rsurface.batchelement3i = rsurface.modelelement3i;
7767         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7768         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7769         rsurface.batchelement3s = rsurface.modelelement3s;
7770         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7771         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7772         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7773         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7774         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7775         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7776         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7777
7778         // if any dynamic vertex processing has to occur in software, we copy the
7779         // entire surface list together before processing to rebase the vertices
7780         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7781         //
7782         // if any gaps exist and we do not have a static vertex buffer, we have to
7783         // copy the surface list together to avoid wasting upload bandwidth on the
7784         // vertices in the gaps.
7785         //
7786         // if gaps exist and we have a static vertex buffer, we can choose whether
7787         // to combine the index buffer ranges into one dynamic index buffer or
7788         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7789         //
7790         // in many cases the batch is reduced to one draw call.
7791
7792         rsurface.batchmultidraw = false;
7793         rsurface.batchmultidrawnumsurfaces = 0;
7794         rsurface.batchmultidrawsurfacelist = NULL;
7795
7796         if (!dynamicvertex)
7797         {
7798                 // static vertex data, just set pointers...
7799                 rsurface.batchgeneratedvertex = false;
7800                 // if there are gaps, we want to build a combined index buffer,
7801                 // otherwise use the original static buffer with an appropriate offset
7802                 if (gaps)
7803                 {
7804                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7805                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7806                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7807                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7808                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7809                         {
7810                                 rsurface.batchmultidraw = true;
7811                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7812                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7813                                 return;
7814                         }
7815                         // build a new triangle elements array for this batch
7816                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7817                         rsurface.batchfirsttriangle = 0;
7818                         numtriangles = 0;
7819                         for (i = 0;i < texturenumsurfaces;i++)
7820                         {
7821                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7822                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7823                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7824                                 numtriangles += surfacenumtriangles;
7825                         }
7826                         rsurface.batchelement3i_indexbuffer = NULL;
7827                         rsurface.batchelement3i_bufferoffset = 0;
7828                         rsurface.batchelement3s = NULL;
7829                         rsurface.batchelement3s_indexbuffer = NULL;
7830                         rsurface.batchelement3s_bufferoffset = 0;
7831                         if (endvertex <= 65536)
7832                         {
7833                                 // make a 16bit (unsigned short) index array if possible
7834                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7835                                 for (i = 0;i < numtriangles*3;i++)
7836                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7837                         }
7838                 }
7839                 else
7840                 {
7841                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7842                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7843                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7844                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7845                 }
7846                 return;
7847         }
7848
7849         // something needs software processing, do it for real...
7850         // we only directly handle separate array data in this case and then
7851         // generate interleaved data if needed...
7852         rsurface.batchgeneratedvertex = true;
7853         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7854         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7855         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7856         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7857
7858         // now copy the vertex data into a combined array and make an index array
7859         // (this is what Quake3 does all the time)
7860         // we also apply any skeletal animation here that would have been done in
7861         // the vertex shader, because most of the dynamic vertex animation cases
7862         // need actual vertex positions and normals
7863         //if (dynamicvertex)
7864         {
7865                 rsurface.batchvertex3f = NULL;
7866                 rsurface.batchvertex3f_vertexbuffer = NULL;
7867                 rsurface.batchvertex3f_bufferoffset = 0;
7868                 rsurface.batchsvector3f = NULL;
7869                 rsurface.batchsvector3f_vertexbuffer = NULL;
7870                 rsurface.batchsvector3f_bufferoffset = 0;
7871                 rsurface.batchtvector3f = NULL;
7872                 rsurface.batchtvector3f_vertexbuffer = NULL;
7873                 rsurface.batchtvector3f_bufferoffset = 0;
7874                 rsurface.batchnormal3f = NULL;
7875                 rsurface.batchnormal3f_vertexbuffer = NULL;
7876                 rsurface.batchnormal3f_bufferoffset = 0;
7877                 rsurface.batchlightmapcolor4f = NULL;
7878                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7879                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7880                 rsurface.batchtexcoordtexture2f = NULL;
7881                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7882                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7883                 rsurface.batchtexcoordlightmap2f = NULL;
7884                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7885                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7886                 rsurface.batchskeletalindex4ub = NULL;
7887                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7888                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7889                 rsurface.batchskeletalweight4ub = NULL;
7890                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7891                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7892                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7893                 rsurface.batchelement3i_indexbuffer = NULL;
7894                 rsurface.batchelement3i_bufferoffset = 0;
7895                 rsurface.batchelement3s = NULL;
7896                 rsurface.batchelement3s_indexbuffer = NULL;
7897                 rsurface.batchelement3s_bufferoffset = 0;
7898                 rsurface.batchskeletaltransform3x4buffer = NULL;
7899                 rsurface.batchskeletaltransform3x4offset = 0;
7900                 rsurface.batchskeletaltransform3x4size = 0;
7901                 // we'll only be setting up certain arrays as needed
7902                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7903                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7904                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7905                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7906                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7907                 {
7908                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7909                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7910                 }
7911                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7912                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7913                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7914                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7915                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7916                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7917                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7918                 {
7919                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7920                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7921                 }
7922                 numvertices = 0;
7923                 numtriangles = 0;
7924                 for (i = 0;i < texturenumsurfaces;i++)
7925                 {
7926                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7927                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7928                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7929                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7930                         // copy only the data requested
7931                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7932                         {
7933                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7934                                 {
7935                                         if (rsurface.batchvertex3f)
7936                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7937                                         else
7938                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7939                                 }
7940                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7941                                 {
7942                                         if (rsurface.modelnormal3f)
7943                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7944                                         else
7945                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7946                                 }
7947                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7948                                 {
7949                                         if (rsurface.modelsvector3f)
7950                                         {
7951                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7952                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7953                                         }
7954                                         else
7955                                         {
7956                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7957                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7958                                         }
7959                                 }
7960                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7961                                 {
7962                                         if (rsurface.modellightmapcolor4f)
7963                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7964                                         else
7965                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7966                                 }
7967                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7968                                 {
7969                                         if (rsurface.modeltexcoordtexture2f)
7970                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7971                                         else
7972                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7973                                 }
7974                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7975                                 {
7976                                         if (rsurface.modeltexcoordlightmap2f)
7977                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7978                                         else
7979                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7980                                 }
7981                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7982                                 {
7983                                         if (rsurface.modelskeletalindex4ub)
7984                                         {
7985                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7986                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7987                                         }
7988                                         else
7989                                         {
7990                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7991                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7992                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7993                                                 for (j = 0;j < surfacenumvertices;j++)
7994                                                         ub[j*4] = 255;
7995                                         }
7996                                 }
7997                         }
7998                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7999                         numvertices += surfacenumvertices;
8000                         numtriangles += surfacenumtriangles;
8001                 }
8002
8003                 // generate a 16bit index array as well if possible
8004                 // (in general, dynamic batches fit)
8005                 if (numvertices <= 65536)
8006                 {
8007                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8008                         for (i = 0;i < numtriangles*3;i++)
8009                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8010                 }
8011
8012                 // since we've copied everything, the batch now starts at 0
8013                 rsurface.batchfirstvertex = 0;
8014                 rsurface.batchnumvertices = batchnumvertices;
8015                 rsurface.batchfirsttriangle = 0;
8016                 rsurface.batchnumtriangles = batchnumtriangles;
8017         }
8018
8019         // apply skeletal animation that would have been done in the vertex shader
8020         if (rsurface.batchskeletaltransform3x4)
8021         {
8022                 const unsigned char *si;
8023                 const unsigned char *sw;
8024                 const float *t[4];
8025                 const float *b = rsurface.batchskeletaltransform3x4;
8026                 float *vp, *vs, *vt, *vn;
8027                 float w[4];
8028                 float m[3][4], n[3][4];
8029                 float tp[3], ts[3], tt[3], tn[3];
8030                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8031                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8032                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8033                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8034                 si = rsurface.batchskeletalindex4ub;
8035                 sw = rsurface.batchskeletalweight4ub;
8036                 vp = rsurface.batchvertex3f;
8037                 vs = rsurface.batchsvector3f;
8038                 vt = rsurface.batchtvector3f;
8039                 vn = rsurface.batchnormal3f;
8040                 memset(m[0], 0, sizeof(m));
8041                 memset(n[0], 0, sizeof(n));
8042                 for (i = 0;i < batchnumvertices;i++)
8043                 {
8044                         t[0] = b + si[0]*12;
8045                         if (sw[0] == 255)
8046                         {
8047                                 // common case - only one matrix
8048                                 m[0][0] = t[0][ 0];
8049                                 m[0][1] = t[0][ 1];
8050                                 m[0][2] = t[0][ 2];
8051                                 m[0][3] = t[0][ 3];
8052                                 m[1][0] = t[0][ 4];
8053                                 m[1][1] = t[0][ 5];
8054                                 m[1][2] = t[0][ 6];
8055                                 m[1][3] = t[0][ 7];
8056                                 m[2][0] = t[0][ 8];
8057                                 m[2][1] = t[0][ 9];
8058                                 m[2][2] = t[0][10];
8059                                 m[2][3] = t[0][11];
8060                         }
8061                         else if (sw[2] + sw[3])
8062                         {
8063                                 // blend 4 matrices
8064                                 t[1] = b + si[1]*12;
8065                                 t[2] = b + si[2]*12;
8066                                 t[3] = b + si[3]*12;
8067                                 w[0] = sw[0] * (1.0f / 255.0f);
8068                                 w[1] = sw[1] * (1.0f / 255.0f);
8069                                 w[2] = sw[2] * (1.0f / 255.0f);
8070                                 w[3] = sw[3] * (1.0f / 255.0f);
8071                                 // blend the matrices
8072                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8073                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8074                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8075                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8076                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8077                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8078                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8079                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8080                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8081                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8082                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8083                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8084                         }
8085                         else
8086                         {
8087                                 // blend 2 matrices
8088                                 t[1] = b + si[1]*12;
8089                                 w[0] = sw[0] * (1.0f / 255.0f);
8090                                 w[1] = sw[1] * (1.0f / 255.0f);
8091                                 // blend the matrices
8092                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8093                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8094                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8095                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8096                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8097                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8098                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8099                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8100                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8101                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8102                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8103                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8104                         }
8105                         si += 4;
8106                         sw += 4;
8107                         // modify the vertex
8108                         VectorCopy(vp, tp);
8109                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8110                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8111                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8112                         vp += 3;
8113                         if (vn)
8114                         {
8115                                 // the normal transformation matrix is a set of cross products...
8116                                 CrossProduct(m[1], m[2], n[0]);
8117                                 CrossProduct(m[2], m[0], n[1]);
8118                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8119                                 VectorCopy(vn, tn);
8120                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8121                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8122                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8123                                 VectorNormalize(vn);
8124                                 vn += 3;
8125                                 if (vs)
8126                                 {
8127                                         VectorCopy(vs, ts);
8128                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8129                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8130                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8131                                         VectorNormalize(vs);
8132                                         vs += 3;
8133                                         VectorCopy(vt, tt);
8134                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8135                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8136                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8137                                         VectorNormalize(vt);
8138                                         vt += 3;
8139                                 }
8140                         }
8141                 }
8142                 rsurface.batchskeletaltransform3x4 = NULL;
8143                 rsurface.batchskeletalnumtransforms = 0;
8144         }
8145
8146         // q1bsp surfaces rendered in vertex color mode have to have colors
8147         // calculated based on lightstyles
8148         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8149         {
8150                 // generate color arrays for the surfaces in this list
8151                 int c[4];
8152                 int scale;
8153                 int size3;
8154                 const int *offsets;
8155                 const unsigned char *lm;
8156                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8157                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8158                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8159                 numvertices = 0;
8160                 for (i = 0;i < texturenumsurfaces;i++)
8161                 {
8162                         surface = texturesurfacelist[i];
8163                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8164                         surfacenumvertices = surface->num_vertices;
8165                         if (surface->lightmapinfo->samples)
8166                         {
8167                                 for (j = 0;j < surfacenumvertices;j++)
8168                                 {
8169                                         lm = surface->lightmapinfo->samples + offsets[j];
8170                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8171                                         VectorScale(lm, scale, c);
8172                                         if (surface->lightmapinfo->styles[1] != 255)
8173                                         {
8174                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8175                                                 lm += size3;
8176                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8177                                                 VectorMA(c, scale, lm, c);
8178                                                 if (surface->lightmapinfo->styles[2] != 255)
8179                                                 {
8180                                                         lm += size3;
8181                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8182                                                         VectorMA(c, scale, lm, c);
8183                                                         if (surface->lightmapinfo->styles[3] != 255)
8184                                                         {
8185                                                                 lm += size3;
8186                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8187                                                                 VectorMA(c, scale, lm, c);
8188                                                         }
8189                                                 }
8190                                         }
8191                                         c[0] >>= 7;
8192                                         c[1] >>= 7;
8193                                         c[2] >>= 7;
8194                                         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);
8195                                         numvertices++;
8196                                 }
8197                         }
8198                         else
8199                         {
8200                                 for (j = 0;j < surfacenumvertices;j++)
8201                                 {
8202                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8203                                         numvertices++;
8204                                 }
8205                         }
8206                 }
8207         }
8208
8209         // if vertices are deformed (sprite flares and things in maps, possibly
8210         // water waves, bulges and other deformations), modify the copied vertices
8211         // in place
8212         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8213         {
8214                 float scale;
8215                 switch (deform->deform)
8216                 {
8217                 default:
8218                 case Q3DEFORM_PROJECTIONSHADOW:
8219                 case Q3DEFORM_TEXT0:
8220                 case Q3DEFORM_TEXT1:
8221                 case Q3DEFORM_TEXT2:
8222                 case Q3DEFORM_TEXT3:
8223                 case Q3DEFORM_TEXT4:
8224                 case Q3DEFORM_TEXT5:
8225                 case Q3DEFORM_TEXT6:
8226                 case Q3DEFORM_TEXT7:
8227                 case Q3DEFORM_NONE:
8228                         break;
8229                 case Q3DEFORM_AUTOSPRITE:
8230                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8231                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8232                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8233                         VectorNormalize(newforward);
8234                         VectorNormalize(newright);
8235                         VectorNormalize(newup);
8236 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8237 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8238 //                      rsurface.batchvertex3f_bufferoffset = 0;
8239 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8240 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8241 //                      rsurface.batchsvector3f_bufferoffset = 0;
8242 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8243 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8244 //                      rsurface.batchtvector3f_bufferoffset = 0;
8245 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8246 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8247 //                      rsurface.batchnormal3f_bufferoffset = 0;
8248                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8249                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8250                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8251                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8252                                 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);
8253                         // a single autosprite surface can contain multiple sprites...
8254                         for (j = 0;j < batchnumvertices - 3;j += 4)
8255                         {
8256                                 VectorClear(center);
8257                                 for (i = 0;i < 4;i++)
8258                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8259                                 VectorScale(center, 0.25f, center);
8260                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8261                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8262                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8263                                 for (i = 0;i < 4;i++)
8264                                 {
8265                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8266                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8267                                 }
8268                         }
8269                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8270                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8271                         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);
8272                         break;
8273                 case Q3DEFORM_AUTOSPRITE2:
8274                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8275                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8276                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8277                         VectorNormalize(newforward);
8278                         VectorNormalize(newright);
8279                         VectorNormalize(newup);
8280 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8281 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8282 //                      rsurface.batchvertex3f_bufferoffset = 0;
8283                         {
8284                                 const float *v1, *v2;
8285                                 vec3_t start, end;
8286                                 float f, l;
8287                                 struct
8288                                 {
8289                                         float length2;
8290                                         const float *v1;
8291                                         const float *v2;
8292                                 }
8293                                 shortest[2];
8294                                 memset(shortest, 0, sizeof(shortest));
8295                                 // a single autosprite surface can contain multiple sprites...
8296                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8297                                 {
8298                                         VectorClear(center);
8299                                         for (i = 0;i < 4;i++)
8300                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8301                                         VectorScale(center, 0.25f, center);
8302                                         // find the two shortest edges, then use them to define the
8303                                         // axis vectors for rotating around the central axis
8304                                         for (i = 0;i < 6;i++)
8305                                         {
8306                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8307                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8308                                                 l = VectorDistance2(v1, v2);
8309                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8310                                                 if (v1[2] != v2[2])
8311                                                         l += (1.0f / 1024.0f);
8312                                                 if (shortest[0].length2 > l || i == 0)
8313                                                 {
8314                                                         shortest[1] = shortest[0];
8315                                                         shortest[0].length2 = l;
8316                                                         shortest[0].v1 = v1;
8317                                                         shortest[0].v2 = v2;
8318                                                 }
8319                                                 else if (shortest[1].length2 > l || i == 1)
8320                                                 {
8321                                                         shortest[1].length2 = l;
8322                                                         shortest[1].v1 = v1;
8323                                                         shortest[1].v2 = v2;
8324                                                 }
8325                                         }
8326                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8327                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8328                                         // this calculates the right vector from the shortest edge
8329                                         // and the up vector from the edge midpoints
8330                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8331                                         VectorNormalize(right);
8332                                         VectorSubtract(end, start, up);
8333                                         VectorNormalize(up);
8334                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8335                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8336                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8337                                         VectorNegate(forward, forward);
8338                                         VectorReflect(forward, 0, up, forward);
8339                                         VectorNormalize(forward);
8340                                         CrossProduct(up, forward, newright);
8341                                         VectorNormalize(newright);
8342                                         // rotate the quad around the up axis vector, this is made
8343                                         // especially easy by the fact we know the quad is flat,
8344                                         // so we only have to subtract the center position and
8345                                         // measure distance along the right vector, and then
8346                                         // multiply that by the newright vector and add back the
8347                                         // center position
8348                                         // we also need to subtract the old position to undo the
8349                                         // displacement from the center, which we do with a
8350                                         // DotProduct, the subtraction/addition of center is also
8351                                         // optimized into DotProducts here
8352                                         l = DotProduct(right, center);
8353                                         for (i = 0;i < 4;i++)
8354                                         {
8355                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8356                                                 f = DotProduct(right, v1) - l;
8357                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8358                                         }
8359                                 }
8360                         }
8361                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8362                         {
8363 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8364 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8365 //                              rsurface.batchnormal3f_bufferoffset = 0;
8366                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8367                         }
8368                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8369                         {
8370 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8371 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8372 //                              rsurface.batchsvector3f_bufferoffset = 0;
8373 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8374 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8375 //                              rsurface.batchtvector3f_bufferoffset = 0;
8376                                 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);
8377                         }
8378                         break;
8379                 case Q3DEFORM_NORMAL:
8380                         // deform the normals to make reflections wavey
8381                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8382                         rsurface.batchnormal3f_vertexbuffer = NULL;
8383                         rsurface.batchnormal3f_bufferoffset = 0;
8384                         for (j = 0;j < batchnumvertices;j++)
8385                         {
8386                                 float vertex[3];
8387                                 float *normal = rsurface.batchnormal3f + 3*j;
8388                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8389                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8390                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8391                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8392                                 VectorNormalize(normal);
8393                         }
8394                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8395                         {
8396 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8397 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8398 //                              rsurface.batchsvector3f_bufferoffset = 0;
8399 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8400 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8401 //                              rsurface.batchtvector3f_bufferoffset = 0;
8402                                 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);
8403                         }
8404                         break;
8405                 case Q3DEFORM_WAVE:
8406                         // deform vertex array to make wavey water and flags and such
8407                         waveparms[0] = deform->waveparms[0];
8408                         waveparms[1] = deform->waveparms[1];
8409                         waveparms[2] = deform->waveparms[2];
8410                         waveparms[3] = deform->waveparms[3];
8411                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8412                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8413                         // this is how a divisor of vertex influence on deformation
8414                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8415                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8416 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8417 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8418 //                      rsurface.batchvertex3f_bufferoffset = 0;
8419 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8420 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8421 //                      rsurface.batchnormal3f_bufferoffset = 0;
8422                         for (j = 0;j < batchnumvertices;j++)
8423                         {
8424                                 // if the wavefunc depends on time, evaluate it per-vertex
8425                                 if (waveparms[3])
8426                                 {
8427                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8428                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8429                                 }
8430                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8431                         }
8432                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8433                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8434                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8435                         {
8436 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8437 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8438 //                              rsurface.batchsvector3f_bufferoffset = 0;
8439 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8440 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8441 //                              rsurface.batchtvector3f_bufferoffset = 0;
8442                                 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);
8443                         }
8444                         break;
8445                 case Q3DEFORM_BULGE:
8446                         // deform vertex array to make the surface have moving bulges
8447 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8448 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8449 //                      rsurface.batchvertex3f_bufferoffset = 0;
8450 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8451 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8452 //                      rsurface.batchnormal3f_bufferoffset = 0;
8453                         for (j = 0;j < batchnumvertices;j++)
8454                         {
8455                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8456                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8457                         }
8458                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8459                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8460                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8461                         {
8462 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8463 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8464 //                              rsurface.batchsvector3f_bufferoffset = 0;
8465 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8466 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8467 //                              rsurface.batchtvector3f_bufferoffset = 0;
8468                                 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);
8469                         }
8470                         break;
8471                 case Q3DEFORM_MOVE:
8472                         // deform vertex array
8473                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8474                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8475                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8476                         VectorScale(deform->parms, scale, waveparms);
8477 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8478 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8479 //                      rsurface.batchvertex3f_bufferoffset = 0;
8480                         for (j = 0;j < batchnumvertices;j++)
8481                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8482                         break;
8483                 }
8484         }
8485
8486         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8487         {
8488         // generate texcoords based on the chosen texcoord source
8489                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8490                 {
8491                 default:
8492                 case Q3TCGEN_TEXTURE:
8493                         break;
8494                 case Q3TCGEN_LIGHTMAP:
8495         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8496         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8497         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8498                         if (rsurface.batchtexcoordlightmap2f)
8499                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8500                         break;
8501                 case Q3TCGEN_VECTOR:
8502         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8503         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8504         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8505                         for (j = 0;j < batchnumvertices;j++)
8506                         {
8507                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8508                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8509                         }
8510                         break;
8511                 case Q3TCGEN_ENVIRONMENT:
8512                         // make environment reflections using a spheremap
8513                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8514                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8515                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8516                         for (j = 0;j < batchnumvertices;j++)
8517                         {
8518                                 // identical to Q3A's method, but executed in worldspace so
8519                                 // carried models can be shiny too
8520
8521                                 float viewer[3], d, reflected[3], worldreflected[3];
8522
8523                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8524                                 // VectorNormalize(viewer);
8525
8526                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8527
8528                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8529                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8530                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8531                                 // note: this is proportinal to viewer, so we can normalize later
8532
8533                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8534                                 VectorNormalize(worldreflected);
8535
8536                                 // note: this sphere map only uses world x and z!
8537                                 // so positive and negative y will LOOK THE SAME.
8538                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8539                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8540                         }
8541                         break;
8542                 }
8543                 // the only tcmod that needs software vertex processing is turbulent, so
8544                 // check for it here and apply the changes if needed
8545                 // and we only support that as the first one
8546                 // (handling a mixture of turbulent and other tcmods would be problematic
8547                 //  without punting it entirely to a software path)
8548                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8549                 {
8550                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8551                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8552         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8553         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8554         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8555                         for (j = 0;j < batchnumvertices;j++)
8556                         {
8557                                 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);
8558                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8559                         }
8560                 }
8561         }
8562 }
8563
8564 void RSurf_DrawBatch(void)
8565 {
8566         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8567         // through the pipeline, killing it earlier in the pipeline would have
8568         // per-surface overhead rather than per-batch overhead, so it's best to
8569         // reject it here, before it hits glDraw.
8570         if (rsurface.batchnumtriangles == 0)
8571                 return;
8572 #if 0
8573         // batch debugging code
8574         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8575         {
8576                 int i;
8577                 int j;
8578                 int c;
8579                 const int *e;
8580                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8581                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8582                 {
8583                         c = e[i];
8584                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8585                         {
8586                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8587                                 {
8588                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8589                                                 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);
8590                                         break;
8591                                 }
8592                         }
8593                 }
8594         }
8595 #endif
8596         if (rsurface.batchmultidraw)
8597         {
8598                 // issue multiple draws rather than copying index data
8599                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8600                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8601                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8602                 for (i = 0;i < numsurfaces;)
8603                 {
8604                         // combine consecutive surfaces as one draw
8605                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8606                                 if (surfacelist[j] != surfacelist[k] + 1)
8607                                         break;
8608                         firstvertex = surfacelist[i]->num_firstvertex;
8609                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8610                         firsttriangle = surfacelist[i]->num_firsttriangle;
8611                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8612                         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);
8613                         i = j;
8614                 }
8615         }
8616         else
8617         {
8618                 // there is only one consecutive run of index data (may have been combined)
8619                 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);
8620         }
8621 }
8622
8623 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8624 {
8625         // pick the closest matching water plane
8626         int planeindex, vertexindex, bestplaneindex = -1;
8627         float d, bestd;
8628         vec3_t vert;
8629         const float *v;
8630         r_waterstate_waterplane_t *p;
8631         qboolean prepared = false;
8632         bestd = 0;
8633         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8634         {
8635                 if(p->camera_entity != rsurface.texture->camera_entity)
8636                         continue;
8637                 d = 0;
8638                 if(!prepared)
8639                 {
8640                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8641                         prepared = true;
8642                         if(rsurface.batchnumvertices == 0)
8643                                 break;
8644                 }
8645                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8646                 {
8647                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8648                         d += fabs(PlaneDiff(vert, &p->plane));
8649                 }
8650                 if (bestd > d || bestplaneindex < 0)
8651                 {
8652                         bestd = d;
8653                         bestplaneindex = planeindex;
8654                 }
8655         }
8656         return bestplaneindex;
8657         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8658         // this situation though, as it might be better to render single larger
8659         // batches with useless stuff (backface culled for example) than to
8660         // render multiple smaller batches
8661 }
8662
8663 void RSurf_SetupDepthAndCulling(void)
8664 {
8665         // submodels are biased to avoid z-fighting with world surfaces that they
8666         // may be exactly overlapping (avoids z-fighting artifacts on certain
8667         // doors and things in Quake maps)
8668         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8669         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8670         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8671         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8672 }
8673
8674 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8675 {
8676         int j;
8677         const float *v;
8678         float p[3], mins[3], maxs[3];
8679         int scissor[4];
8680         // transparent sky would be ridiculous
8681         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8682                 return;
8683         R_SetupShader_Generic_NoTexture(false, false);
8684         skyrenderlater = true;
8685         RSurf_SetupDepthAndCulling();
8686         GL_DepthMask(true);
8687
8688         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8689         if (r_sky_scissor.integer)
8690         {
8691                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8692                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8693                 {
8694                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8695                         if (j > 0)
8696                         {
8697                                 if (mins[0] > p[0]) mins[0] = p[0];
8698                                 if (mins[1] > p[1]) mins[1] = p[1];
8699                                 if (mins[2] > p[2]) mins[2] = p[2];
8700                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8701                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8702                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8703                         }
8704                         else
8705                         {
8706                                 VectorCopy(p, mins);
8707                                 VectorCopy(p, maxs);
8708                         }
8709                 }
8710                 if (!R_ScissorForBBox(mins, maxs, scissor))
8711                 {
8712                         if (skyscissor[2])
8713                         {
8714                                 if (skyscissor[0] > scissor[0])
8715                                 {
8716                                         skyscissor[2] += skyscissor[0] - scissor[0];
8717                                         skyscissor[0] = scissor[0];
8718                                 }
8719                                 if (skyscissor[1] > scissor[1])
8720                                 {
8721                                         skyscissor[3] += skyscissor[1] - scissor[1];
8722                                         skyscissor[1] = scissor[1];
8723                                 }
8724                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8725                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8726                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8727                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8728                         }
8729                         else
8730                                 Vector4Copy(scissor, skyscissor);
8731                 }
8732         }
8733
8734         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8735         // skymasking on them, and Quake3 never did sky masking (unlike
8736         // software Quake and software Quake2), so disable the sky masking
8737         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8738         // and skymasking also looks very bad when noclipping outside the
8739         // level, so don't use it then either.
8740         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)
8741         {
8742                 R_Mesh_ResetTextureState();
8743                 if (skyrendermasked)
8744                 {
8745                         R_SetupShader_DepthOrShadow(false, false, false);
8746                         // depth-only (masking)
8747                         GL_ColorMask(0, 0, 0, 0);
8748                         // just to make sure that braindead drivers don't draw
8749                         // anything despite that colormask...
8750                         GL_BlendFunc(GL_ZERO, GL_ONE);
8751                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8752                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8753                 }
8754                 else
8755                 {
8756                         R_SetupShader_Generic_NoTexture(false, false);
8757                         // fog sky
8758                         GL_BlendFunc(GL_ONE, GL_ZERO);
8759                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8760                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8761                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8762                 }
8763                 RSurf_DrawBatch();
8764                 if (skyrendermasked)
8765                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8766         }
8767         R_Mesh_ResetTextureState();
8768         GL_Color(1, 1, 1, 1);
8769 }
8770
8771 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8772 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8773 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8774 {
8775         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8776                 return;
8777         if (prepass)
8778         {
8779                 // render screenspace normalmap to texture
8780                 GL_DepthMask(true);
8781                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8782                 RSurf_DrawBatch();
8783                 return;
8784         }
8785
8786         // bind lightmap texture
8787
8788         // water/refraction/reflection/camera surfaces have to be handled specially
8789         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8790         {
8791                 int start, end, startplaneindex;
8792                 for (start = 0;start < texturenumsurfaces;start = end)
8793                 {
8794                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8795                         if(startplaneindex < 0)
8796                         {
8797                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8798                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8799                                 end = start + 1;
8800                                 continue;
8801                         }
8802                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8803                                 ;
8804                         // now that we have a batch using the same planeindex, render it
8805                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8806                         {
8807                                 // render water or distortion background
8808                                 GL_DepthMask(true);
8809                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8810                                 RSurf_DrawBatch();
8811                                 // blend surface on top
8812                                 GL_DepthMask(false);
8813                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8814                                 RSurf_DrawBatch();
8815                         }
8816                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8817                         {
8818                                 // render surface with reflection texture as input
8819                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8820                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8821                                 RSurf_DrawBatch();
8822                         }
8823                 }
8824                 return;
8825         }
8826
8827         // render surface batch normally
8828         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8829         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8830         RSurf_DrawBatch();
8831 }
8832
8833 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8834 {
8835         int vi;
8836         int j;
8837         int texturesurfaceindex;
8838         int k;
8839         const msurface_t *surface;
8840         float surfacecolor4f[4];
8841
8842 //      R_Mesh_ResetTextureState();
8843         R_SetupShader_Generic_NoTexture(false, false);
8844
8845         GL_BlendFunc(GL_ONE, GL_ZERO);
8846         GL_DepthMask(writedepth);
8847
8848         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8849         vi = 0;
8850         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8851         {
8852                 surface = texturesurfacelist[texturesurfaceindex];
8853                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8854                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8855                 for (j = 0;j < surface->num_vertices;j++)
8856                 {
8857                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8858                         vi++;
8859                 }
8860         }
8861         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8862         RSurf_DrawBatch();
8863 }
8864
8865 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8866 {
8867         CHECKGLERROR
8868         RSurf_SetupDepthAndCulling();
8869         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8870         {
8871                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8872                 return;
8873         }
8874         switch (vid.renderpath)
8875         {
8876         case RENDERPATH_GL32:
8877         case RENDERPATH_GLES2:
8878                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8879                 break;
8880         }
8881         CHECKGLERROR
8882 }
8883
8884 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8885 {
8886         int i, j;
8887         int texturenumsurfaces, endsurface;
8888         texture_t *texture;
8889         const msurface_t *surface;
8890         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8891
8892         RSurf_ActiveModelEntity(ent, true, true, false);
8893
8894         if (r_transparentdepthmasking.integer)
8895         {
8896                 qboolean setup = false;
8897                 for (i = 0;i < numsurfaces;i = j)
8898                 {
8899                         j = i + 1;
8900                         surface = rsurface.modelsurfaces + surfacelist[i];
8901                         texture = surface->texture;
8902                         rsurface.texture = R_GetCurrentTexture(texture);
8903                         rsurface.lightmaptexture = NULL;
8904                         rsurface.deluxemaptexture = NULL;
8905                         rsurface.uselightmaptexture = false;
8906                         // scan ahead until we find a different texture
8907                         endsurface = min(i + 1024, numsurfaces);
8908                         texturenumsurfaces = 0;
8909                         texturesurfacelist[texturenumsurfaces++] = surface;
8910                         for (;j < endsurface;j++)
8911                         {
8912                                 surface = rsurface.modelsurfaces + surfacelist[j];
8913                                 if (texture != surface->texture)
8914                                         break;
8915                                 texturesurfacelist[texturenumsurfaces++] = surface;
8916                         }
8917                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8918                                 continue;
8919                         // render the range of surfaces as depth
8920                         if (!setup)
8921                         {
8922                                 setup = true;
8923                                 GL_ColorMask(0,0,0,0);
8924                                 GL_Color(1,1,1,1);
8925                                 GL_DepthTest(true);
8926                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8927                                 GL_DepthMask(true);
8928 //                              R_Mesh_ResetTextureState();
8929                         }
8930                         RSurf_SetupDepthAndCulling();
8931                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8932                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8933                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8934                         RSurf_DrawBatch();
8935                 }
8936                 if (setup)
8937                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8938         }
8939
8940         for (i = 0;i < numsurfaces;i = j)
8941         {
8942                 j = i + 1;
8943                 surface = rsurface.modelsurfaces + surfacelist[i];
8944                 texture = surface->texture;
8945                 rsurface.texture = R_GetCurrentTexture(texture);
8946                 // scan ahead until we find a different texture
8947                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8948                 texturenumsurfaces = 0;
8949                 texturesurfacelist[texturenumsurfaces++] = surface;
8950                         rsurface.lightmaptexture = surface->lightmaptexture;
8951                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8952                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8953                         for (;j < endsurface;j++)
8954                         {
8955                                 surface = rsurface.modelsurfaces + surfacelist[j];
8956                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8957                                         break;
8958                                 texturesurfacelist[texturenumsurfaces++] = surface;
8959                         }
8960                 // render the range of surfaces
8961                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8962         }
8963         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8964 }
8965
8966 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8967 {
8968         // transparent surfaces get pushed off into the transparent queue
8969         int surfacelistindex;
8970         const msurface_t *surface;
8971         vec3_t tempcenter, center;
8972         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8973         {
8974                 surface = texturesurfacelist[surfacelistindex];
8975                 if (r_transparent_sortsurfacesbynearest.integer)
8976                 {
8977                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8978                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8979                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8980                 }
8981                 else
8982                 {
8983                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8984                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8985                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8986                 }
8987                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8988                 if (rsurface.entity->transparent_offset) // transparent offset
8989                 {
8990                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8991                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8992                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8993                 }
8994                 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);
8995         }
8996 }
8997
8998 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8999 {
9000         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9001                 return;
9002         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9003                 return;
9004         RSurf_SetupDepthAndCulling();
9005         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9006         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9007         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9008         RSurf_DrawBatch();
9009 }
9010
9011 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9012 {
9013         CHECKGLERROR
9014         if (ui)
9015                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9016         else if (depthonly)
9017                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9018         else if (prepass)
9019         {
9020                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9021                         return;
9022                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9023                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9024                 else
9025                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9026         }
9027         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9028                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9029         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9030                 return;
9031         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9032         {
9033                 // in the deferred case, transparent surfaces were queued during prepass
9034                 if (!r_shadow_usingdeferredprepass)
9035                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9036         }
9037         else
9038         {
9039                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9040                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9041         }
9042         CHECKGLERROR
9043 }
9044
9045 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9046 {
9047         int i, j;
9048         texture_t *texture;
9049         R_FrameData_SetMark();
9050         // break the surface list down into batches by texture and use of lightmapping
9051         for (i = 0;i < numsurfaces;i = j)
9052         {
9053                 j = i + 1;
9054                 // texture is the base texture pointer, rsurface.texture is the
9055                 // current frame/skin the texture is directing us to use (for example
9056                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9057                 // use skin 1 instead)
9058                 texture = surfacelist[i]->texture;
9059                 rsurface.texture = R_GetCurrentTexture(texture);
9060                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9061                 {
9062                         // if this texture is not the kind we want, skip ahead to the next one
9063                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9064                                 ;
9065                         continue;
9066                 }
9067                 if(depthonly || prepass)
9068                 {
9069                         rsurface.lightmaptexture = NULL;
9070                         rsurface.deluxemaptexture = NULL;
9071                         rsurface.uselightmaptexture = false;
9072                         // simply scan ahead until we find a different texture or lightmap state
9073                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9074                                 ;
9075                 }
9076                 else
9077                 {
9078                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9079                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9080                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9081                         // simply scan ahead until we find a different texture or lightmap state
9082                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9083                                 ;
9084                 }
9085                 // render the range of surfaces
9086                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9087         }
9088         R_FrameData_ReturnToMark();
9089 }
9090
9091 float locboxvertex3f[6*4*3] =
9092 {
9093         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9094         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9095         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9096         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9097         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9098         1,0,0, 0,0,0, 0,1,0, 1,1,0
9099 };
9100
9101 unsigned short locboxelements[6*2*3] =
9102 {
9103          0, 1, 2, 0, 2, 3,
9104          4, 5, 6, 4, 6, 7,
9105          8, 9,10, 8,10,11,
9106         12,13,14, 12,14,15,
9107         16,17,18, 16,18,19,
9108         20,21,22, 20,22,23
9109 };
9110
9111 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9112 {
9113         int i, j;
9114         cl_locnode_t *loc = (cl_locnode_t *)ent;
9115         vec3_t mins, size;
9116         float vertex3f[6*4*3];
9117         CHECKGLERROR
9118         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9119         GL_DepthMask(false);
9120         GL_DepthRange(0, 1);
9121         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9122         GL_DepthTest(true);
9123         GL_CullFace(GL_NONE);
9124         R_EntityMatrix(&identitymatrix);
9125
9126 //      R_Mesh_ResetTextureState();
9127
9128         i = surfacelist[0];
9129         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9130                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9131                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9132                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9133
9134         if (VectorCompare(loc->mins, loc->maxs))
9135         {
9136                 VectorSet(size, 2, 2, 2);
9137                 VectorMA(loc->mins, -0.5f, size, mins);
9138         }
9139         else
9140         {
9141                 VectorCopy(loc->mins, mins);
9142                 VectorSubtract(loc->maxs, loc->mins, size);
9143         }
9144
9145         for (i = 0;i < 6*4*3;)
9146                 for (j = 0;j < 3;j++, i++)
9147                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9148
9149         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9150         R_SetupShader_Generic_NoTexture(false, false);
9151         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9152 }
9153
9154 void R_DrawLocs(void)
9155 {
9156         int index;
9157         cl_locnode_t *loc, *nearestloc;
9158         vec3_t center;
9159         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9160         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9161         {
9162                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9163                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9164         }
9165 }
9166
9167 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9168 {
9169         if (decalsystem->decals)
9170                 Mem_Free(decalsystem->decals);
9171         memset(decalsystem, 0, sizeof(*decalsystem));
9172 }
9173
9174 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)
9175 {
9176         tridecal_t *decal;
9177         tridecal_t *decals;
9178         int i;
9179
9180         // expand or initialize the system
9181         if (decalsystem->maxdecals <= decalsystem->numdecals)
9182         {
9183                 decalsystem_t old = *decalsystem;
9184                 qboolean useshortelements;
9185                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9186                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9187                 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)));
9188                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9189                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9190                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9191                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9192                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9193                 if (decalsystem->numdecals)
9194                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9195                 if (old.decals)
9196                         Mem_Free(old.decals);
9197                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9198                         decalsystem->element3i[i] = i;
9199                 if (useshortelements)
9200                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9201                                 decalsystem->element3s[i] = i;
9202         }
9203
9204         // grab a decal and search for another free slot for the next one
9205         decals = decalsystem->decals;
9206         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9207         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9208                 ;
9209         decalsystem->freedecal = i;
9210         if (decalsystem->numdecals <= i)
9211                 decalsystem->numdecals = i + 1;
9212
9213         // initialize the decal
9214         decal->lived = 0;
9215         decal->triangleindex = triangleindex;
9216         decal->surfaceindex = surfaceindex;
9217         decal->decalsequence = decalsequence;
9218         decal->color4f[0][0] = c0[0];
9219         decal->color4f[0][1] = c0[1];
9220         decal->color4f[0][2] = c0[2];
9221         decal->color4f[0][3] = 1;
9222         decal->color4f[1][0] = c1[0];
9223         decal->color4f[1][1] = c1[1];
9224         decal->color4f[1][2] = c1[2];
9225         decal->color4f[1][3] = 1;
9226         decal->color4f[2][0] = c2[0];
9227         decal->color4f[2][1] = c2[1];
9228         decal->color4f[2][2] = c2[2];
9229         decal->color4f[2][3] = 1;
9230         decal->vertex3f[0][0] = v0[0];
9231         decal->vertex3f[0][1] = v0[1];
9232         decal->vertex3f[0][2] = v0[2];
9233         decal->vertex3f[1][0] = v1[0];
9234         decal->vertex3f[1][1] = v1[1];
9235         decal->vertex3f[1][2] = v1[2];
9236         decal->vertex3f[2][0] = v2[0];
9237         decal->vertex3f[2][1] = v2[1];
9238         decal->vertex3f[2][2] = v2[2];
9239         decal->texcoord2f[0][0] = t0[0];
9240         decal->texcoord2f[0][1] = t0[1];
9241         decal->texcoord2f[1][0] = t1[0];
9242         decal->texcoord2f[1][1] = t1[1];
9243         decal->texcoord2f[2][0] = t2[0];
9244         decal->texcoord2f[2][1] = t2[1];
9245         TriangleNormal(v0, v1, v2, decal->plane);
9246         VectorNormalize(decal->plane);
9247         decal->plane[3] = DotProduct(v0, decal->plane);
9248 }
9249
9250 extern cvar_t cl_decals_bias;
9251 extern cvar_t cl_decals_models;
9252 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9253 // baseparms, parms, temps
9254 static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9255 {
9256         int cornerindex;
9257         int index;
9258         float v[9][3];
9259         const float *vertex3f;
9260         const float *normal3f;
9261         int numpoints;
9262         float points[2][9][3];
9263         float temp[3];
9264         float tc[9][2];
9265         float f;
9266         float c[9][4];
9267         const int *e;
9268
9269         e = rsurface.modelelement3i + 3*triangleindex;
9270
9271         vertex3f = rsurface.modelvertex3f;
9272         normal3f = rsurface.modelnormal3f;
9273
9274         if (normal3f)
9275         {
9276                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9277                 {
9278                         index = 3*e[cornerindex];
9279                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9280                 }
9281         }
9282         else
9283         {
9284                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9285                 {
9286                         index = 3*e[cornerindex];
9287                         VectorCopy(vertex3f + index, v[cornerindex]);
9288                 }
9289         }
9290
9291         // cull backfaces
9292         //TriangleNormal(v[0], v[1], v[2], normal);
9293         //if (DotProduct(normal, localnormal) < 0.0f)
9294         //      continue;
9295         // clip by each of the box planes formed from the projection matrix
9296         // if anything survives, we emit the decal
9297         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]);
9298         if (numpoints < 3)
9299                 return;
9300         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]);
9301         if (numpoints < 3)
9302                 return;
9303         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]);
9304         if (numpoints < 3)
9305                 return;
9306         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]);
9307         if (numpoints < 3)
9308                 return;
9309         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]);
9310         if (numpoints < 3)
9311                 return;
9312         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]);
9313         if (numpoints < 3)
9314                 return;
9315         // some part of the triangle survived, so we have to accept it...
9316         if (dynamic)
9317         {
9318                 // dynamic always uses the original triangle
9319                 numpoints = 3;
9320                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9321                 {
9322                         index = 3*e[cornerindex];
9323                         VectorCopy(vertex3f + index, v[cornerindex]);
9324                 }
9325         }
9326         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9327         {
9328                 // convert vertex positions to texcoords
9329                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9330                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9331                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9332                 // calculate distance fade from the projection origin
9333                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9334                 f = bound(0.0f, f, 1.0f);
9335                 c[cornerindex][0] = r * f;
9336                 c[cornerindex][1] = g * f;
9337                 c[cornerindex][2] = b * f;
9338                 c[cornerindex][3] = 1.0f;
9339                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9340         }
9341         if (dynamic)
9342                 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);
9343         else
9344                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9345                         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);
9346 }
9347 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)
9348 {
9349         matrix4x4_t projection;
9350         decalsystem_t *decalsystem;
9351         qboolean dynamic;
9352         dp_model_t *model;
9353         const msurface_t *surface;
9354         const msurface_t *surfaces;
9355         const int *surfacelist;
9356         const texture_t *texture;
9357         int numtriangles;
9358         int numsurfacelist;
9359         int surfacelistindex;
9360         int surfaceindex;
9361         int triangleindex;
9362         float localorigin[3];
9363         float localnormal[3];
9364         float localmins[3];
9365         float localmaxs[3];
9366         float localsize;
9367         //float normal[3];
9368         float planes[6][4];
9369         float angles[3];
9370         bih_t *bih;
9371         int bih_triangles_count;
9372         int bih_triangles[256];
9373         int bih_surfaces[256];
9374
9375         decalsystem = &ent->decalsystem;
9376         model = ent->model;
9377         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9378         {
9379                 R_DecalSystem_Reset(&ent->decalsystem);
9380                 return;
9381         }
9382
9383         if (!model->brush.data_leafs && !cl_decals_models.integer)
9384         {
9385                 if (decalsystem->model)
9386                         R_DecalSystem_Reset(decalsystem);
9387                 return;
9388         }
9389
9390         if (decalsystem->model != model)
9391                 R_DecalSystem_Reset(decalsystem);
9392         decalsystem->model = model;
9393
9394         RSurf_ActiveModelEntity(ent, true, false, false);
9395
9396         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9397         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9398         VectorNormalize(localnormal);
9399         localsize = worldsize*rsurface.inversematrixscale;
9400         localmins[0] = localorigin[0] - localsize;
9401         localmins[1] = localorigin[1] - localsize;
9402         localmins[2] = localorigin[2] - localsize;
9403         localmaxs[0] = localorigin[0] + localsize;
9404         localmaxs[1] = localorigin[1] + localsize;
9405         localmaxs[2] = localorigin[2] + localsize;
9406
9407         //VectorCopy(localnormal, planes[4]);
9408         //VectorVectors(planes[4], planes[2], planes[0]);
9409         AnglesFromVectors(angles, localnormal, NULL, false);
9410         AngleVectors(angles, planes[0], planes[2], planes[4]);
9411         VectorNegate(planes[0], planes[1]);
9412         VectorNegate(planes[2], planes[3]);
9413         VectorNegate(planes[4], planes[5]);
9414         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9415         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9416         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9417         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9418         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9419         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9420
9421 #if 1
9422 // works
9423 {
9424         matrix4x4_t forwardprojection;
9425         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9426         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9427 }
9428 #else
9429 // broken
9430 {
9431         float projectionvector[4][3];
9432         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9433         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9434         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9435         projectionvector[0][0] = planes[0][0] * ilocalsize;
9436         projectionvector[0][1] = planes[1][0] * ilocalsize;
9437         projectionvector[0][2] = planes[2][0] * ilocalsize;
9438         projectionvector[1][0] = planes[0][1] * ilocalsize;
9439         projectionvector[1][1] = planes[1][1] * ilocalsize;
9440         projectionvector[1][2] = planes[2][1] * ilocalsize;
9441         projectionvector[2][0] = planes[0][2] * ilocalsize;
9442         projectionvector[2][1] = planes[1][2] * ilocalsize;
9443         projectionvector[2][2] = planes[2][2] * ilocalsize;
9444         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9445         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9446         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9447         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9448 }
9449 #endif
9450
9451         dynamic = model->surfmesh.isanimated;
9452         numsurfacelist = model->nummodelsurfaces;
9453         surfacelist = model->sortedmodelsurfaces;
9454         surfaces = model->data_surfaces;
9455
9456         bih = NULL;
9457         bih_triangles_count = -1;
9458         if(!dynamic)
9459         {
9460                 if(model->render_bih.numleafs)
9461                         bih = &model->render_bih;
9462                 else if(model->collision_bih.numleafs)
9463                         bih = &model->collision_bih;
9464         }
9465         if(bih)
9466                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9467         if(bih_triangles_count == 0)
9468                 return;
9469         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9470                 return;
9471         if(bih_triangles_count > 0)
9472         {
9473                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9474                 {
9475                         surfaceindex = bih_surfaces[triangleindex];
9476                         surface = surfaces + surfaceindex;
9477                         texture = surface->texture;
9478                         if (!texture)
9479                                 continue;
9480                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9481                                 continue;
9482                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9483                                 continue;
9484                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9485                 }
9486         }
9487         else
9488         {
9489                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9490                 {
9491                         surfaceindex = surfacelist[surfacelistindex];
9492                         surface = surfaces + surfaceindex;
9493                         // check cull box first because it rejects more than any other check
9494                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9495                                 continue;
9496                         // skip transparent surfaces
9497                         texture = surface->texture;
9498                         if (!texture)
9499                                 continue;
9500                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9501                                 continue;
9502                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9503                                 continue;
9504                         numtriangles = surface->num_triangles;
9505                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9506                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9507                 }
9508         }
9509 }
9510
9511 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9512 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)
9513 {
9514         int renderentityindex;
9515         float worldmins[3];
9516         float worldmaxs[3];
9517         entity_render_t *ent;
9518
9519         worldmins[0] = worldorigin[0] - worldsize;
9520         worldmins[1] = worldorigin[1] - worldsize;
9521         worldmins[2] = worldorigin[2] - worldsize;
9522         worldmaxs[0] = worldorigin[0] + worldsize;
9523         worldmaxs[1] = worldorigin[1] + worldsize;
9524         worldmaxs[2] = worldorigin[2] + worldsize;
9525
9526         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9527
9528         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9529         {
9530                 ent = r_refdef.scene.entities[renderentityindex];
9531                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9532                         continue;
9533
9534                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9535         }
9536 }
9537
9538 typedef struct r_decalsystem_splatqueue_s
9539 {
9540         vec3_t worldorigin;
9541         vec3_t worldnormal;
9542         float color[4];
9543         float tcrange[4];
9544         float worldsize;
9545         unsigned int decalsequence;
9546 }
9547 r_decalsystem_splatqueue_t;
9548
9549 int r_decalsystem_numqueued = 0;
9550 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9551
9552 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)
9553 {
9554         r_decalsystem_splatqueue_t *queue;
9555
9556         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9557                 return;
9558
9559         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9560         VectorCopy(worldorigin, queue->worldorigin);
9561         VectorCopy(worldnormal, queue->worldnormal);
9562         Vector4Set(queue->color, r, g, b, a);
9563         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9564         queue->worldsize = worldsize;
9565         queue->decalsequence = cl.decalsequence++;
9566 }
9567
9568 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9569 {
9570         int i;
9571         r_decalsystem_splatqueue_t *queue;
9572
9573         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9574                 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);
9575         r_decalsystem_numqueued = 0;
9576 }
9577
9578 extern cvar_t cl_decals_max;
9579 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9580 {
9581         int i;
9582         decalsystem_t *decalsystem = &ent->decalsystem;
9583         int numdecals;
9584         unsigned int killsequence;
9585         tridecal_t *decal;
9586         float frametime;
9587         float lifetime;
9588
9589         if (!decalsystem->numdecals)
9590                 return;
9591
9592         if (r_showsurfaces.integer)
9593                 return;
9594
9595         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9596         {
9597                 R_DecalSystem_Reset(decalsystem);
9598                 return;
9599         }
9600
9601         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9602         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9603
9604         if (decalsystem->lastupdatetime)
9605                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9606         else
9607                 frametime = 0;
9608         decalsystem->lastupdatetime = r_refdef.scene.time;
9609         numdecals = decalsystem->numdecals;
9610
9611         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9612         {
9613                 if (decal->color4f[0][3])
9614                 {
9615                         decal->lived += frametime;
9616                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9617                         {
9618                                 memset(decal, 0, sizeof(*decal));
9619                                 if (decalsystem->freedecal > i)
9620                                         decalsystem->freedecal = i;
9621                         }
9622                 }
9623         }
9624         decal = decalsystem->decals;
9625         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9626                 numdecals--;
9627
9628         // collapse the array by shuffling the tail decals into the gaps
9629         for (;;)
9630         {
9631                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9632                         decalsystem->freedecal++;
9633                 if (decalsystem->freedecal == numdecals)
9634                         break;
9635                 decal[decalsystem->freedecal] = decal[--numdecals];
9636         }
9637
9638         decalsystem->numdecals = numdecals;
9639
9640         if (numdecals <= 0)
9641         {
9642                 // if there are no decals left, reset decalsystem
9643                 R_DecalSystem_Reset(decalsystem);
9644         }
9645 }
9646
9647 extern skinframe_t *decalskinframe;
9648 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9649 {
9650         int i;
9651         decalsystem_t *decalsystem = &ent->decalsystem;
9652         int numdecals;
9653         tridecal_t *decal;
9654         float faderate;
9655         float alpha;
9656         float *v3f;
9657         float *c4f;
9658         float *t2f;
9659         const int *e;
9660         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9661         int numtris = 0;
9662
9663         numdecals = decalsystem->numdecals;
9664         if (!numdecals)
9665                 return;
9666
9667         if (r_showsurfaces.integer)
9668                 return;
9669
9670         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9671         {
9672                 R_DecalSystem_Reset(decalsystem);
9673                 return;
9674         }
9675
9676         // if the model is static it doesn't matter what value we give for
9677         // wantnormals and wanttangents, so this logic uses only rules applicable
9678         // to a model, knowing that they are meaningless otherwise
9679         RSurf_ActiveModelEntity(ent, false, false, false);
9680
9681         decalsystem->lastupdatetime = r_refdef.scene.time;
9682
9683         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9684
9685         // update vertex positions for animated models
9686         v3f = decalsystem->vertex3f;
9687         c4f = decalsystem->color4f;
9688         t2f = decalsystem->texcoord2f;
9689         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9690         {
9691                 if (!decal->color4f[0][3])
9692                         continue;
9693
9694                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9695                         continue;
9696
9697                 // skip backfaces
9698                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9699                         continue;
9700
9701                 // update color values for fading decals
9702                 if (decal->lived >= cl_decals_time.value)
9703                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9704                 else
9705                         alpha = 1.0f;
9706
9707                 c4f[ 0] = decal->color4f[0][0] * alpha;
9708                 c4f[ 1] = decal->color4f[0][1] * alpha;
9709                 c4f[ 2] = decal->color4f[0][2] * alpha;
9710                 c4f[ 3] = 1;
9711                 c4f[ 4] = decal->color4f[1][0] * alpha;
9712                 c4f[ 5] = decal->color4f[1][1] * alpha;
9713                 c4f[ 6] = decal->color4f[1][2] * alpha;
9714                 c4f[ 7] = 1;
9715                 c4f[ 8] = decal->color4f[2][0] * alpha;
9716                 c4f[ 9] = decal->color4f[2][1] * alpha;
9717                 c4f[10] = decal->color4f[2][2] * alpha;
9718                 c4f[11] = 1;
9719
9720                 t2f[0] = decal->texcoord2f[0][0];
9721                 t2f[1] = decal->texcoord2f[0][1];
9722                 t2f[2] = decal->texcoord2f[1][0];
9723                 t2f[3] = decal->texcoord2f[1][1];
9724                 t2f[4] = decal->texcoord2f[2][0];
9725                 t2f[5] = decal->texcoord2f[2][1];
9726
9727                 // update vertex positions for animated models
9728                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9729                 {
9730                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9731                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9732                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9733                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9734                 }
9735                 else
9736                 {
9737                         VectorCopy(decal->vertex3f[0], v3f);
9738                         VectorCopy(decal->vertex3f[1], v3f + 3);
9739                         VectorCopy(decal->vertex3f[2], v3f + 6);
9740                 }
9741
9742                 if (r_refdef.fogenabled)
9743                 {
9744                         alpha = RSurf_FogVertex(v3f);
9745                         VectorScale(c4f, alpha, c4f);
9746                         alpha = RSurf_FogVertex(v3f + 3);
9747                         VectorScale(c4f + 4, alpha, c4f + 4);
9748                         alpha = RSurf_FogVertex(v3f + 6);
9749                         VectorScale(c4f + 8, alpha, c4f + 8);
9750                 }
9751
9752                 v3f += 9;
9753                 c4f += 12;
9754                 t2f += 6;
9755                 numtris++;
9756         }
9757
9758         if (numtris > 0)
9759         {
9760                 r_refdef.stats[r_stat_drawndecals] += numtris;
9761
9762                 // now render the decals all at once
9763                 // (this assumes they all use one particle font texture!)
9764                 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);
9765 //              R_Mesh_ResetTextureState();
9766                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9767                 GL_DepthMask(false);
9768                 GL_DepthRange(0, 1);
9769                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9770                 GL_DepthTest(true);
9771                 GL_CullFace(GL_NONE);
9772                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9773                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9774                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9775         }
9776 }
9777
9778 static void R_DrawModelDecals(void)
9779 {
9780         int i, numdecals;
9781
9782         // fade faster when there are too many decals
9783         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9784         for (i = 0;i < r_refdef.scene.numentities;i++)
9785                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9786
9787         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9788         for (i = 0;i < r_refdef.scene.numentities;i++)
9789                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9790                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9791
9792         R_DecalSystem_ApplySplatEntitiesQueue();
9793
9794         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9795         for (i = 0;i < r_refdef.scene.numentities;i++)
9796                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9797
9798         r_refdef.stats[r_stat_totaldecals] += numdecals;
9799
9800         if (r_showsurfaces.integer || !r_drawdecals.integer)
9801                 return;
9802
9803         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9804
9805         for (i = 0;i < r_refdef.scene.numentities;i++)
9806         {
9807                 if (!r_refdef.viewcache.entityvisible[i])
9808                         continue;
9809                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9810                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9811         }
9812 }
9813
9814 static void R_DrawDebugModel(void)
9815 {
9816         entity_render_t *ent = rsurface.entity;
9817         int i, j, flagsmask;
9818         const msurface_t *surface;
9819         dp_model_t *model = ent->model;
9820
9821         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9822                 return;
9823
9824         if (r_showoverdraw.value > 0)
9825         {
9826                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9827                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9828                 R_SetupShader_Generic_NoTexture(false, false);
9829                 GL_DepthTest(false);
9830                 GL_DepthMask(false);
9831                 GL_DepthRange(0, 1);
9832                 GL_BlendFunc(GL_ONE, GL_ONE);
9833                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9834                 {
9835                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9836                                 continue;
9837                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9838                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9839                         {
9840                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9841                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9842                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9843                                         GL_Color(c, 0, 0, 1.0f);
9844                                 else if (ent == r_refdef.scene.worldentity)
9845                                         GL_Color(c, c, c, 1.0f);
9846                                 else
9847                                         GL_Color(0, c, 0, 1.0f);
9848                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9849                                 RSurf_DrawBatch();
9850                         }
9851                 }
9852                 rsurface.texture = NULL;
9853         }
9854
9855         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9856
9857 //      R_Mesh_ResetTextureState();
9858         R_SetupShader_Generic_NoTexture(false, false);
9859         GL_DepthRange(0, 1);
9860         GL_DepthTest(!r_showdisabledepthtest.integer);
9861         GL_DepthMask(false);
9862         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9863
9864         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9865         {
9866                 int triangleindex;
9867                 int bihleafindex;
9868                 qboolean cullbox = false;
9869                 const q3mbrush_t *brush;
9870                 const bih_t *bih = &model->collision_bih;
9871                 const bih_leaf_t *bihleaf;
9872                 float vertex3f[3][3];
9873                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9874                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9875                 {
9876                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9877                                 continue;
9878                         switch (bihleaf->type)
9879                         {
9880                         case BIH_BRUSH:
9881                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9882                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9883                                 {
9884                                         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);
9885                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9886                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9887                                 }
9888                                 break;
9889                         case BIH_COLLISIONTRIANGLE:
9890                                 triangleindex = bihleaf->itemindex;
9891                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9892                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9893                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9894                                 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);
9895                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9896                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9897                                 break;
9898                         case BIH_RENDERTRIANGLE:
9899                                 triangleindex = bihleaf->itemindex;
9900                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9901                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9902                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9903                                 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);
9904                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9905                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9906                                 break;
9907                         }
9908                 }
9909         }
9910
9911         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9912
9913 #ifndef USE_GLES2
9914         if (r_showtris.value > 0 && qglPolygonMode)
9915         {
9916                 if (r_showdisabledepthtest.integer)
9917                 {
9918                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9919                         GL_DepthMask(false);
9920                 }
9921                 else
9922                 {
9923                         GL_BlendFunc(GL_ONE, GL_ZERO);
9924                         GL_DepthMask(true);
9925                 }
9926                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9927                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9928                 {
9929                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9930                                 continue;
9931                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9932                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9933                         {
9934                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9935                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9936                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9937                                 else if (ent == r_refdef.scene.worldentity)
9938                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9939                                 else
9940                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9941                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9942                                 RSurf_DrawBatch();
9943                         }
9944                 }
9945                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9946                 rsurface.texture = NULL;
9947         }
9948
9949 # if 0
9950         // FIXME!  implement r_shownormals with just triangles
9951         if (r_shownormals.value != 0 && qglBegin)
9952         {
9953                 int l, k;
9954                 vec3_t v;
9955                 if (r_showdisabledepthtest.integer)
9956                 {
9957                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9958                         GL_DepthMask(false);
9959                 }
9960                 else
9961                 {
9962                         GL_BlendFunc(GL_ONE, GL_ZERO);
9963                         GL_DepthMask(true);
9964                 }
9965                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9966                 {
9967                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9968                                 continue;
9969                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9970                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9971                         {
9972                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9973                                 qglBegin(GL_LINES);
9974                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9975                                 {
9976                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9977                                         {
9978                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9979                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9980                                                 qglVertex3f(v[0], v[1], v[2]);
9981                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9982                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9983                                                 qglVertex3f(v[0], v[1], v[2]);
9984                                         }
9985                                 }
9986                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9987                                 {
9988                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9989                                         {
9990                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9991                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9992                                                 qglVertex3f(v[0], v[1], v[2]);
9993                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9994                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9995                                                 qglVertex3f(v[0], v[1], v[2]);
9996                                         }
9997                                 }
9998                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9999                                 {
10000                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10001                                         {
10002                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10003                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10004                                                 qglVertex3f(v[0], v[1], v[2]);
10005                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10006                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10007                                                 qglVertex3f(v[0], v[1], v[2]);
10008                                         }
10009                                 }
10010                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10011                                 {
10012                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10013                                         {
10014                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10015                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10016                                                 qglVertex3f(v[0], v[1], v[2]);
10017                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10018                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10019                                                 qglVertex3f(v[0], v[1], v[2]);
10020                                         }
10021                                 }
10022                                 qglEnd();
10023                                 CHECKGLERROR
10024                         }
10025                 }
10026                 rsurface.texture = NULL;
10027         }
10028 # endif
10029 #endif
10030 }
10031
10032 int r_maxsurfacelist = 0;
10033 const msurface_t **r_surfacelist = NULL;
10034 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10035 {
10036         int i, j, endj, flagsmask;
10037         dp_model_t *model = ent->model;
10038         msurface_t *surfaces;
10039         unsigned char *update;
10040         int numsurfacelist = 0;
10041         if (model == NULL)
10042                 return;
10043
10044         if (r_maxsurfacelist < model->num_surfaces)
10045         {
10046                 r_maxsurfacelist = model->num_surfaces;
10047                 if (r_surfacelist)
10048                         Mem_Free((msurface_t **)r_surfacelist);
10049                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10050         }
10051
10052         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10053                 RSurf_ActiveModelEntity(ent, false, false, false);
10054         else if (prepass)
10055                 RSurf_ActiveModelEntity(ent, true, true, true);
10056         else if (depthonly)
10057                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10058         else
10059                 RSurf_ActiveModelEntity(ent, true, true, false);
10060
10061         surfaces = model->data_surfaces;
10062         update = model->brushq1.lightmapupdateflags;
10063
10064         // update light styles
10065         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10066         {
10067                 model_brush_lightstyleinfo_t *style;
10068                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10069                 {
10070                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10071                         {
10072                                 int *list = style->surfacelist;
10073                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10074                                 for (j = 0;j < style->numsurfaces;j++)
10075                                         update[list[j]] = true;
10076                         }
10077                 }
10078         }
10079
10080         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10081
10082         if (debug)
10083         {
10084                 R_DrawDebugModel();
10085                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10086                 return;
10087         }
10088
10089         rsurface.lightmaptexture = NULL;
10090         rsurface.deluxemaptexture = NULL;
10091         rsurface.uselightmaptexture = false;
10092         rsurface.texture = NULL;
10093         rsurface.rtlight = NULL;
10094         numsurfacelist = 0;
10095         // add visible surfaces to draw list
10096         if (ent == r_refdef.scene.worldentity)
10097         {
10098                 // for the world entity, check surfacevisible
10099                 for (i = 0;i < model->nummodelsurfaces;i++)
10100                 {
10101                         j = model->sortedmodelsurfaces[i];
10102                         if (r_refdef.viewcache.world_surfacevisible[j])
10103                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10104                 }
10105         }
10106         else if (ui)
10107         {
10108                 // for ui we have to preserve the order of surfaces
10109                 for (i = 0; i < model->nummodelsurfaces; i++)
10110                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10111         }
10112         else
10113         {
10114                 // add all surfaces
10115                 for (i = 0; i < model->nummodelsurfaces; i++)
10116                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10117         }
10118         // don't do anything if there were no surfaces
10119         if (!numsurfacelist)
10120         {
10121                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10122                 return;
10123         }
10124         // update lightmaps if needed
10125         if (update)
10126         {
10127                 int updated = 0;
10128                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10129                 {
10130                         if (update[j])
10131                         {
10132                                 updated++;
10133                                 R_BuildLightMap(ent, surfaces + j);
10134                         }
10135                 }
10136         }
10137
10138         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10139
10140         // add to stats if desired
10141         if (r_speeds.integer && !skysurfaces && !depthonly)
10142         {
10143                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10144                 for (j = 0;j < numsurfacelist;j++)
10145                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10146         }
10147
10148         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10149 }
10150
10151 void R_DebugLine(vec3_t start, vec3_t end)
10152 {
10153         dp_model_t *mod = CL_Mesh_UI();
10154         msurface_t *surf;
10155         int e0, e1, e2, e3;
10156         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10157         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10158         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10159         vec4_t w[2], s[2];
10160
10161         // transform to screen coords first
10162         Vector4Set(w[0], start[0], start[1], start[2], 1);
10163         Vector4Set(w[1], end[0], end[1], end[2], 1);
10164         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10165         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10166         x1 = s[0][0] * vid_conwidth.value / vid.width;
10167         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10168         x2 = s[1][0] * vid_conwidth.value / vid.width;
10169         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10170         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10171
10172         // add the line to the UI mesh for drawing later
10173
10174         // width is measured in real pixels
10175         if (fabs(x2 - x1) > fabs(y2 - y1))
10176         {
10177                 offsetx = 0;
10178                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10179         }
10180         else
10181         {
10182                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10183                 offsety = 0;
10184         }
10185         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);
10186         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10187         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10188         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10189         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10190         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10191         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10192
10193 }
10194
10195
10196 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10197 {
10198         static texture_t texture;
10199
10200         // fake enough texture and surface state to render this geometry
10201
10202         texture.update_lastrenderframe = -1; // regenerate this texture
10203         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10204         texture.basealpha = 1.0f;
10205         texture.currentskinframe = skinframe;
10206         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10207         texture.offsetmapping = OFFSETMAPPING_OFF;
10208         texture.offsetscale = 1;
10209         texture.specularscalemod = 1;
10210         texture.specularpowermod = 1;
10211         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10212
10213         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10214 }
10215
10216 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10217 {
10218         static msurface_t surface;
10219         const msurface_t *surfacelist = &surface;
10220
10221         // fake enough texture and surface state to render this geometry
10222         surface.texture = texture;
10223         surface.num_triangles = numtriangles;
10224         surface.num_firsttriangle = firsttriangle;
10225         surface.num_vertices = numvertices;
10226         surface.num_firstvertex = firstvertex;
10227
10228         // now render it
10229         rsurface.texture = R_GetCurrentTexture(surface.texture);
10230         rsurface.lightmaptexture = NULL;
10231         rsurface.deluxemaptexture = NULL;
10232         rsurface.uselightmaptexture = false;
10233         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10234 }