]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Convert \ to / when loading texture from Q3 shader
[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_Printf(CON_ERROR "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 && !notrippy)
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_local[0], t->render_modellight_lightdir_local[1], t->render_modellight_lightdir_local[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_world[q] = q == 2;
6735                         t->render_modellight_lightdir_local[q] = q == 2;
6736                         t->render_modellight_ambient[q] = 1;
6737                         t->render_modellight_diffuse[q] = 0;
6738                         t->render_modellight_specular[q] = 0;
6739                         t->render_lightmap_ambient[q] = 0;
6740                         t->render_lightmap_diffuse[q] = 0;
6741                         t->render_lightmap_specular[q] = 0;
6742                         t->render_rtlight_diffuse[q] = 0;
6743                         t->render_rtlight_specular[q] = 0;
6744                 }
6745         }
6746         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6747         {
6748                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6749                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6750                 for (q = 0; q < 3; q++)
6751                 {
6752                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6753                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6754                         t->render_modellight_lightdir_world[q] = q == 2;
6755                         t->render_modellight_lightdir_local[q] = q == 2;
6756                         t->render_modellight_diffuse[q] = 0;
6757                         t->render_modellight_specular[q] = 0;
6758                         t->render_lightmap_ambient[q] = 0;
6759                         t->render_lightmap_diffuse[q] = 0;
6760                         t->render_lightmap_specular[q] = 0;
6761                         t->render_rtlight_diffuse[q] = 0;
6762                         t->render_rtlight_specular[q] = 0;
6763                 }
6764         }
6765         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6766         {
6767                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6768                 for (q = 0; q < 3; q++)
6769                 {
6770                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6771                         t->render_modellight_lightdir_world[q] = q == 2;
6772                         t->render_modellight_lightdir_local[q] = q == 2;
6773                         t->render_modellight_ambient[q] = 0;
6774                         t->render_modellight_diffuse[q] = 0;
6775                         t->render_modellight_specular[q] = 0;
6776                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6777                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6778                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6779                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6780                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6781                 }
6782         }
6783         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6784         {
6785                 // ambient + single direction light (modellight)
6786                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6787                 for (q = 0; q < 3; q++)
6788                 {
6789                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6790                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6791                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6792                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6793                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6794                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6795                         t->render_lightmap_ambient[q] = 0;
6796                         t->render_lightmap_diffuse[q] = 0;
6797                         t->render_lightmap_specular[q] = 0;
6798                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6799                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6800                 }
6801         }
6802         else
6803         {
6804                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6805                 for (q = 0; q < 3; q++)
6806                 {
6807                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6808                         t->render_modellight_lightdir_world[q] = q == 2;
6809                         t->render_modellight_lightdir_local[q] = q == 2;
6810                         t->render_modellight_ambient[q] = 0;
6811                         t->render_modellight_diffuse[q] = 0;
6812                         t->render_modellight_specular[q] = 0;
6813                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6814                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6815                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6816                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6817                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6818                 }
6819         }
6820
6821         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6822         {
6823                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6824                 // attribute, we punt it to the lightmap path and hope for the best,
6825                 // but lighting doesn't work.
6826                 //
6827                 // FIXME: this is fine for effects but CSQC polygons should be subject
6828                 // to lighting.
6829                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6830                 for (q = 0; q < 3; q++)
6831                 {
6832                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6833                         t->render_modellight_lightdir_world[q] = q == 2;
6834                         t->render_modellight_lightdir_local[q] = q == 2;
6835                         t->render_modellight_ambient[q] = 0;
6836                         t->render_modellight_diffuse[q] = 0;
6837                         t->render_modellight_specular[q] = 0;
6838                         t->render_lightmap_ambient[q] = 0;
6839                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6840                         t->render_lightmap_specular[q] = 0;
6841                         t->render_rtlight_diffuse[q] = 0;
6842                         t->render_rtlight_specular[q] = 0;
6843                 }
6844         }
6845
6846         for (q = 0; q < 3; q++)
6847         {
6848                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6849                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6850         }
6851
6852         if (rsurface.ent_flags & RENDER_ADDITIVE)
6853                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6854         else if (t->currentalpha < 1)
6855                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6856         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6857         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6858                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6859         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6860                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6861         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6862                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6863         if (t->backgroundshaderpass)
6864                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6865         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6866         {
6867                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6868                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6869         }
6870         else
6871                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6872         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6873         {
6874                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6875                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6876         }
6877         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6878                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6879
6880         // there is no tcmod
6881         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6882         {
6883                 t->currenttexmatrix = r_waterscrollmatrix;
6884                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6885         }
6886         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6887         {
6888                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6889                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6890         }
6891
6892         if (t->materialshaderpass)
6893                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6894                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6895
6896         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6897         if (t->currentskinframe->qpixels)
6898                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6899         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6900         if (!t->basetexture)
6901                 t->basetexture = r_texture_notexture;
6902         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6903         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6904         t->nmaptexture = t->currentskinframe->nmap;
6905         if (!t->nmaptexture)
6906                 t->nmaptexture = r_texture_blanknormalmap;
6907         t->glosstexture = r_texture_black;
6908         t->glowtexture = t->currentskinframe->glow;
6909         t->fogtexture = t->currentskinframe->fog;
6910         t->reflectmasktexture = t->currentskinframe->reflect;
6911         if (t->backgroundshaderpass)
6912         {
6913                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6914                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6915                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6916                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6917                 t->backgroundglosstexture = r_texture_black;
6918                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6919                 if (!t->backgroundnmaptexture)
6920                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6921                 // make sure that if glow is going to be used, both textures are not NULL
6922                 if (!t->backgroundglowtexture && t->glowtexture)
6923                         t->backgroundglowtexture = r_texture_black;
6924                 if (!t->glowtexture && t->backgroundglowtexture)
6925                         t->glowtexture = r_texture_black;
6926         }
6927         else
6928         {
6929                 t->backgroundbasetexture = r_texture_white;
6930                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6931                 t->backgroundglosstexture = r_texture_black;
6932                 t->backgroundglowtexture = NULL;
6933         }
6934         t->specularpower = r_shadow_glossexponent.value;
6935         // TODO: store reference values for these in the texture?
6936         if (r_shadow_gloss.integer > 0)
6937         {
6938                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6939                 {
6940                         if (r_shadow_glossintensity.value > 0)
6941                         {
6942                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6943                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6944                                 specularscale = r_shadow_glossintensity.value;
6945                         }
6946                 }
6947                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6948                 {
6949                         t->glosstexture = r_texture_white;
6950                         t->backgroundglosstexture = r_texture_white;
6951                         specularscale = r_shadow_gloss2intensity.value;
6952                         t->specularpower = r_shadow_gloss2exponent.value;
6953                 }
6954         }
6955         specularscale *= t->specularscalemod;
6956         t->specularpower *= t->specularpowermod;
6957
6958         // lightmaps mode looks bad with dlights using actual texturing, so turn
6959         // off the colormap and glossmap, but leave the normalmap on as it still
6960         // accurately represents the shading involved
6961         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6962         {
6963                 t->basetexture = r_texture_grey128;
6964                 t->pantstexture = r_texture_black;
6965                 t->shirttexture = r_texture_black;
6966                 if (gl_lightmaps.integer < 2)
6967                         t->nmaptexture = r_texture_blanknormalmap;
6968                 t->glosstexture = r_texture_black;
6969                 t->glowtexture = NULL;
6970                 t->fogtexture = NULL;
6971                 t->reflectmasktexture = NULL;
6972                 t->backgroundbasetexture = NULL;
6973                 if (gl_lightmaps.integer < 2)
6974                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6975                 t->backgroundglosstexture = r_texture_black;
6976                 t->backgroundglowtexture = NULL;
6977                 specularscale = 0;
6978                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6979         }
6980
6981         if (specularscale != 1.0f)
6982         {
6983                 for (q = 0; q < 3; q++)
6984                 {
6985                         t->render_modellight_specular[q] *= specularscale;
6986                         t->render_lightmap_specular[q] *= specularscale;
6987                         t->render_rtlight_specular[q] *= specularscale;
6988                 }
6989         }
6990
6991         t->currentblendfunc[0] = GL_ONE;
6992         t->currentblendfunc[1] = GL_ZERO;
6993         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6994         {
6995                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6996                 t->currentblendfunc[1] = GL_ONE;
6997         }
6998         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6999         {
7000                 t->currentblendfunc[0] = GL_SRC_ALPHA;
7001                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
7002         }
7003         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7004         {
7005                 t->currentblendfunc[0] = t->customblendfunc[0];
7006                 t->currentblendfunc[1] = t->customblendfunc[1];
7007         }
7008
7009         return t;
7010 }
7011
7012 rsurfacestate_t rsurface;
7013
7014 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7015 {
7016         dp_model_t *model = ent->model;
7017         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7018         //      return;
7019         rsurface.entity = (entity_render_t *)ent;
7020         rsurface.skeleton = ent->skeleton;
7021         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7022         rsurface.ent_skinnum = ent->skinnum;
7023         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;
7024         rsurface.ent_flags = ent->flags;
7025         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7026                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7027         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7028         rsurface.matrix = ent->matrix;
7029         rsurface.inversematrix = ent->inversematrix;
7030         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7031         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7032         R_EntityMatrix(&rsurface.matrix);
7033         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7034         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7035         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7036         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7037         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7038         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7039         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7040         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7041         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7042         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7043         if (ent->model->brush.submodel && !prepass)
7044         {
7045                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7046                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7047         }
7048         // if the animcache code decided it should use the shader path, skip the deform step
7049         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7050         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7051         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7052         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7053         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7054         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7055         {
7056                 if (ent->animcache_vertex3f)
7057                 {
7058                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7059                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7060                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7061                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7062                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7063                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7064                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7065                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7066                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7067                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7068                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7069                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7070                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7071                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7072                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7073                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7074                 }
7075                 else if (wanttangents)
7076                 {
7077                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7078                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7079                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7080                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7081                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7082                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7083                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7084                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7085                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7086                         rsurface.modelvertex3f_vertexbuffer = NULL;
7087                         rsurface.modelvertex3f_bufferoffset = 0;
7088                         rsurface.modelvertex3f_vertexbuffer = 0;
7089                         rsurface.modelvertex3f_bufferoffset = 0;
7090                         rsurface.modelsvector3f_vertexbuffer = 0;
7091                         rsurface.modelsvector3f_bufferoffset = 0;
7092                         rsurface.modeltvector3f_vertexbuffer = 0;
7093                         rsurface.modeltvector3f_bufferoffset = 0;
7094                         rsurface.modelnormal3f_vertexbuffer = 0;
7095                         rsurface.modelnormal3f_bufferoffset = 0;
7096                 }
7097                 else if (wantnormals)
7098                 {
7099                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7100                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7101                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7102                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7103                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7104                         rsurface.modelsvector3f = NULL;
7105                         rsurface.modeltvector3f = NULL;
7106                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7107                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7108                         rsurface.modelvertex3f_vertexbuffer = NULL;
7109                         rsurface.modelvertex3f_bufferoffset = 0;
7110                         rsurface.modelvertex3f_vertexbuffer = 0;
7111                         rsurface.modelvertex3f_bufferoffset = 0;
7112                         rsurface.modelsvector3f_vertexbuffer = 0;
7113                         rsurface.modelsvector3f_bufferoffset = 0;
7114                         rsurface.modeltvector3f_vertexbuffer = 0;
7115                         rsurface.modeltvector3f_bufferoffset = 0;
7116                         rsurface.modelnormal3f_vertexbuffer = 0;
7117                         rsurface.modelnormal3f_bufferoffset = 0;
7118                 }
7119                 else
7120                 {
7121                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7122                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7123                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7124                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7125                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7126                         rsurface.modelsvector3f = NULL;
7127                         rsurface.modeltvector3f = NULL;
7128                         rsurface.modelnormal3f = NULL;
7129                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7130                         rsurface.modelvertex3f_vertexbuffer = NULL;
7131                         rsurface.modelvertex3f_bufferoffset = 0;
7132                         rsurface.modelvertex3f_vertexbuffer = 0;
7133                         rsurface.modelvertex3f_bufferoffset = 0;
7134                         rsurface.modelsvector3f_vertexbuffer = 0;
7135                         rsurface.modelsvector3f_bufferoffset = 0;
7136                         rsurface.modeltvector3f_vertexbuffer = 0;
7137                         rsurface.modeltvector3f_bufferoffset = 0;
7138                         rsurface.modelnormal3f_vertexbuffer = 0;
7139                         rsurface.modelnormal3f_bufferoffset = 0;
7140                 }
7141                 rsurface.modelgeneratedvertex = true;
7142         }
7143         else
7144         {
7145                 if (rsurface.entityskeletaltransform3x4)
7146                 {
7147                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7148                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7149                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7150                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7151                 }
7152                 else
7153                 {
7154                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7155                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7156                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7157                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7158                 }
7159                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7160                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7161                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7162                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7163                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7164                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7165                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7166                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7167                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7168                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7169                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7170                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7171                 rsurface.modelgeneratedvertex = false;
7172         }
7173         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7174         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7175         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7176         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7177         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7178         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7179         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7180         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7181         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7182         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7183         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7184         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7185         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7186         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7187         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7188         rsurface.modelelement3i = model->surfmesh.data_element3i;
7189         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7190         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7191         rsurface.modelelement3s = model->surfmesh.data_element3s;
7192         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7193         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7194         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7195         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7196         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7197         rsurface.modelsurfaces = model->data_surfaces;
7198         rsurface.batchgeneratedvertex = false;
7199         rsurface.batchfirstvertex = 0;
7200         rsurface.batchnumvertices = 0;
7201         rsurface.batchfirsttriangle = 0;
7202         rsurface.batchnumtriangles = 0;
7203         rsurface.batchvertex3f  = NULL;
7204         rsurface.batchvertex3f_vertexbuffer = NULL;
7205         rsurface.batchvertex3f_bufferoffset = 0;
7206         rsurface.batchsvector3f = NULL;
7207         rsurface.batchsvector3f_vertexbuffer = NULL;
7208         rsurface.batchsvector3f_bufferoffset = 0;
7209         rsurface.batchtvector3f = NULL;
7210         rsurface.batchtvector3f_vertexbuffer = NULL;
7211         rsurface.batchtvector3f_bufferoffset = 0;
7212         rsurface.batchnormal3f  = NULL;
7213         rsurface.batchnormal3f_vertexbuffer = NULL;
7214         rsurface.batchnormal3f_bufferoffset = 0;
7215         rsurface.batchlightmapcolor4f = NULL;
7216         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7217         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7218         rsurface.batchtexcoordtexture2f = NULL;
7219         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7220         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7221         rsurface.batchtexcoordlightmap2f = NULL;
7222         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7223         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7224         rsurface.batchskeletalindex4ub = NULL;
7225         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7226         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7227         rsurface.batchskeletalweight4ub = NULL;
7228         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7229         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7230         rsurface.batchelement3i = NULL;
7231         rsurface.batchelement3i_indexbuffer = NULL;
7232         rsurface.batchelement3i_bufferoffset = 0;
7233         rsurface.batchelement3s = NULL;
7234         rsurface.batchelement3s_indexbuffer = NULL;
7235         rsurface.batchelement3s_bufferoffset = 0;
7236         rsurface.forcecurrenttextureupdate = false;
7237 }
7238
7239 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)
7240 {
7241         rsurface.entity = r_refdef.scene.worldentity;
7242         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7243                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7244                 // A better approach could be making this copy only once per frame.
7245                 static entity_render_t custom_entity;
7246                 int q;
7247                 custom_entity = *rsurface.entity;
7248                 for (q = 0; q < 3; ++q) {
7249                         float colormod = q == 0 ? r : q == 1 ? g : b;
7250                         custom_entity.render_fullbright[q] *= colormod;
7251                         custom_entity.render_modellight_ambient[q] *= colormod;
7252                         custom_entity.render_modellight_diffuse[q] *= colormod;
7253                         custom_entity.render_lightmap_ambient[q] *= colormod;
7254                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7255                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7256                 }
7257                 custom_entity.alpha *= a;
7258                 rsurface.entity = &custom_entity;
7259         }
7260         rsurface.skeleton = NULL;
7261         rsurface.ent_skinnum = 0;
7262         rsurface.ent_qwskin = -1;
7263         rsurface.ent_flags = entflags;
7264         rsurface.shadertime = r_refdef.scene.time - shadertime;
7265         rsurface.modelnumvertices = numvertices;
7266         rsurface.modelnumtriangles = numtriangles;
7267         rsurface.matrix = *matrix;
7268         rsurface.inversematrix = *inversematrix;
7269         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7270         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7271         R_EntityMatrix(&rsurface.matrix);
7272         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7273         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7274         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7275         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7276         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7277         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7278         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7279         rsurface.frameblend[0].lerp = 1;
7280         rsurface.ent_alttextures = false;
7281         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7282         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7283         rsurface.entityskeletaltransform3x4 = NULL;
7284         rsurface.entityskeletaltransform3x4buffer = NULL;
7285         rsurface.entityskeletaltransform3x4offset = 0;
7286         rsurface.entityskeletaltransform3x4size = 0;
7287         rsurface.entityskeletalnumtransforms = 0;
7288         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7289         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7290         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7291         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7292         if (wanttangents)
7293         {
7294                 rsurface.modelvertex3f = (float *)vertex3f;
7295                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7296                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7297                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7298         }
7299         else if (wantnormals)
7300         {
7301                 rsurface.modelvertex3f = (float *)vertex3f;
7302                 rsurface.modelsvector3f = NULL;
7303                 rsurface.modeltvector3f = NULL;
7304                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7305         }
7306         else
7307         {
7308                 rsurface.modelvertex3f = (float *)vertex3f;
7309                 rsurface.modelsvector3f = NULL;
7310                 rsurface.modeltvector3f = NULL;
7311                 rsurface.modelnormal3f = NULL;
7312         }
7313         rsurface.modelvertex3f_vertexbuffer = 0;
7314         rsurface.modelvertex3f_bufferoffset = 0;
7315         rsurface.modelsvector3f_vertexbuffer = 0;
7316         rsurface.modelsvector3f_bufferoffset = 0;
7317         rsurface.modeltvector3f_vertexbuffer = 0;
7318         rsurface.modeltvector3f_bufferoffset = 0;
7319         rsurface.modelnormal3f_vertexbuffer = 0;
7320         rsurface.modelnormal3f_bufferoffset = 0;
7321         rsurface.modelgeneratedvertex = true;
7322         rsurface.modellightmapcolor4f  = (float *)color4f;
7323         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7324         rsurface.modellightmapcolor4f_bufferoffset = 0;
7325         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7326         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7327         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7328         rsurface.modeltexcoordlightmap2f  = NULL;
7329         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7330         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7331         rsurface.modelskeletalindex4ub = NULL;
7332         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7333         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7334         rsurface.modelskeletalweight4ub = NULL;
7335         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7336         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7337         rsurface.modelelement3i = (int *)element3i;
7338         rsurface.modelelement3i_indexbuffer = NULL;
7339         rsurface.modelelement3i_bufferoffset = 0;
7340         rsurface.modelelement3s = (unsigned short *)element3s;
7341         rsurface.modelelement3s_indexbuffer = NULL;
7342         rsurface.modelelement3s_bufferoffset = 0;
7343         rsurface.modellightmapoffsets = NULL;
7344         rsurface.modelsurfaces = NULL;
7345         rsurface.batchgeneratedvertex = false;
7346         rsurface.batchfirstvertex = 0;
7347         rsurface.batchnumvertices = 0;
7348         rsurface.batchfirsttriangle = 0;
7349         rsurface.batchnumtriangles = 0;
7350         rsurface.batchvertex3f  = NULL;
7351         rsurface.batchvertex3f_vertexbuffer = NULL;
7352         rsurface.batchvertex3f_bufferoffset = 0;
7353         rsurface.batchsvector3f = NULL;
7354         rsurface.batchsvector3f_vertexbuffer = NULL;
7355         rsurface.batchsvector3f_bufferoffset = 0;
7356         rsurface.batchtvector3f = NULL;
7357         rsurface.batchtvector3f_vertexbuffer = NULL;
7358         rsurface.batchtvector3f_bufferoffset = 0;
7359         rsurface.batchnormal3f  = NULL;
7360         rsurface.batchnormal3f_vertexbuffer = NULL;
7361         rsurface.batchnormal3f_bufferoffset = 0;
7362         rsurface.batchlightmapcolor4f = NULL;
7363         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7364         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7365         rsurface.batchtexcoordtexture2f = NULL;
7366         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7367         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7368         rsurface.batchtexcoordlightmap2f = NULL;
7369         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7370         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7371         rsurface.batchskeletalindex4ub = NULL;
7372         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7373         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7374         rsurface.batchskeletalweight4ub = NULL;
7375         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7376         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7377         rsurface.batchelement3i = NULL;
7378         rsurface.batchelement3i_indexbuffer = NULL;
7379         rsurface.batchelement3i_bufferoffset = 0;
7380         rsurface.batchelement3s = NULL;
7381         rsurface.batchelement3s_indexbuffer = NULL;
7382         rsurface.batchelement3s_bufferoffset = 0;
7383         rsurface.forcecurrenttextureupdate = true;
7384
7385         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7386         {
7387                 if ((wantnormals || wanttangents) && !normal3f)
7388                 {
7389                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7390                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7391                 }
7392                 if (wanttangents && !svector3f)
7393                 {
7394                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7395                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7396                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7397                 }
7398         }
7399 }
7400
7401 float RSurf_FogPoint(const float *v)
7402 {
7403         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7404         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7405         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7406         float FogHeightFade = r_refdef.fogheightfade;
7407         float fogfrac;
7408         unsigned int fogmasktableindex;
7409         if (r_refdef.fogplaneviewabove)
7410                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7411         else
7412                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7413         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7414         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7415 }
7416
7417 float RSurf_FogVertex(const float *v)
7418 {
7419         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7420         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7421         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7422         float FogHeightFade = rsurface.fogheightfade;
7423         float fogfrac;
7424         unsigned int fogmasktableindex;
7425         if (r_refdef.fogplaneviewabove)
7426                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7427         else
7428                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7429         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7430         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7431 }
7432
7433 void RSurf_UploadBuffersForBatch(void)
7434 {
7435         // 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)
7436         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7437         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7438                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7439         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7440                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7441         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7442                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7443         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7444                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7445         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7446                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7447         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7448                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7449         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7450                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7451         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7452                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7453         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7454                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7455
7456         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7457                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7458         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7459                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7460
7461         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7462         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7463         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7464         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7465         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7466         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7467         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7468         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7469         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7470         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7471 }
7472
7473 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7474 {
7475         int i;
7476         for (i = 0;i < numelements;i++)
7477                 outelement3i[i] = inelement3i[i] + adjust;
7478 }
7479
7480 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7481 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7482 {
7483         int deformindex;
7484         int firsttriangle;
7485         int numtriangles;
7486         int firstvertex;
7487         int endvertex;
7488         int numvertices;
7489         int surfacefirsttriangle;
7490         int surfacenumtriangles;
7491         int surfacefirstvertex;
7492         int surfaceendvertex;
7493         int surfacenumvertices;
7494         int batchnumsurfaces = texturenumsurfaces;
7495         int batchnumvertices;
7496         int batchnumtriangles;
7497         int i, j;
7498         qboolean gaps;
7499         qboolean dynamicvertex;
7500         float amplitude;
7501         float animpos;
7502         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7503         float waveparms[4];
7504         unsigned char *ub;
7505         q3shaderinfo_deform_t *deform;
7506         const msurface_t *surface, *firstsurface;
7507         if (!texturenumsurfaces)
7508                 return;
7509         // find vertex range of this surface batch
7510         gaps = false;
7511         firstsurface = texturesurfacelist[0];
7512         firsttriangle = firstsurface->num_firsttriangle;
7513         batchnumvertices = 0;
7514         batchnumtriangles = 0;
7515         firstvertex = endvertex = firstsurface->num_firstvertex;
7516         for (i = 0;i < texturenumsurfaces;i++)
7517         {
7518                 surface = texturesurfacelist[i];
7519                 if (surface != firstsurface + i)
7520                         gaps = true;
7521                 surfacefirstvertex = surface->num_firstvertex;
7522                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7523                 surfacenumvertices = surface->num_vertices;
7524                 surfacenumtriangles = surface->num_triangles;
7525                 if (firstvertex > surfacefirstvertex)
7526                         firstvertex = surfacefirstvertex;
7527                 if (endvertex < surfaceendvertex)
7528                         endvertex = surfaceendvertex;
7529                 batchnumvertices += surfacenumvertices;
7530                 batchnumtriangles += surfacenumtriangles;
7531         }
7532
7533         r_refdef.stats[r_stat_batch_batches]++;
7534         if (gaps)
7535                 r_refdef.stats[r_stat_batch_withgaps]++;
7536         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7537         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7538         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7539
7540         // we now know the vertex range used, and if there are any gaps in it
7541         rsurface.batchfirstvertex = firstvertex;
7542         rsurface.batchnumvertices = endvertex - firstvertex;
7543         rsurface.batchfirsttriangle = firsttriangle;
7544         rsurface.batchnumtriangles = batchnumtriangles;
7545
7546         // check if any dynamic vertex processing must occur
7547         dynamicvertex = false;
7548
7549         // we must use vertexbuffers for rendering, we can upload vertex buffers
7550         // easily enough but if the basevertex is non-zero it becomes more
7551         // difficult, so force dynamicvertex path in that case - it's suboptimal
7552         // but the most optimal case is to have the geometry sources provide their
7553         // own anyway.
7554         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7555                 dynamicvertex = true;
7556
7557         // a cvar to force the dynamic vertex path to be taken, for debugging
7558         if (r_batch_debugdynamicvertexpath.integer)
7559         {
7560                 if (!dynamicvertex)
7561                 {
7562                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7563                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7564                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7565                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7566                 }
7567                 dynamicvertex = true;
7568         }
7569
7570         // if there is a chance of animated vertex colors, it's a dynamic batch
7571         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7572         {
7573                 if (!dynamicvertex)
7574                 {
7575                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7576                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7577                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7578                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7579                 }
7580                 dynamicvertex = true;
7581         }
7582
7583         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7584         {
7585                 switch (deform->deform)
7586                 {
7587                 default:
7588                 case Q3DEFORM_PROJECTIONSHADOW:
7589                 case Q3DEFORM_TEXT0:
7590                 case Q3DEFORM_TEXT1:
7591                 case Q3DEFORM_TEXT2:
7592                 case Q3DEFORM_TEXT3:
7593                 case Q3DEFORM_TEXT4:
7594                 case Q3DEFORM_TEXT5:
7595                 case Q3DEFORM_TEXT6:
7596                 case Q3DEFORM_TEXT7:
7597                 case Q3DEFORM_NONE:
7598                         break;
7599                 case Q3DEFORM_AUTOSPRITE:
7600                         if (!dynamicvertex)
7601                         {
7602                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7603                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7604                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7605                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7606                         }
7607                         dynamicvertex = true;
7608                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7609                         break;
7610                 case Q3DEFORM_AUTOSPRITE2:
7611                         if (!dynamicvertex)
7612                         {
7613                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7614                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7615                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7616                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7617                         }
7618                         dynamicvertex = true;
7619                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7620                         break;
7621                 case Q3DEFORM_NORMAL:
7622                         if (!dynamicvertex)
7623                         {
7624                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7625                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7626                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7627                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7628                         }
7629                         dynamicvertex = true;
7630                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7631                         break;
7632                 case Q3DEFORM_WAVE:
7633                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7634                                 break; // if wavefunc is a nop, ignore this transform
7635                         if (!dynamicvertex)
7636                         {
7637                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7638                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7639                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7640                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7641                         }
7642                         dynamicvertex = true;
7643                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7644                         break;
7645                 case Q3DEFORM_BULGE:
7646                         if (!dynamicvertex)
7647                         {
7648                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7649                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7650                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7651                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7652                         }
7653                         dynamicvertex = true;
7654                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7655                         break;
7656                 case Q3DEFORM_MOVE:
7657                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7658                                 break; // if wavefunc is a nop, ignore this transform
7659                         if (!dynamicvertex)
7660                         {
7661                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7662                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7663                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7664                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7665                         }
7666                         dynamicvertex = true;
7667                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7668                         break;
7669                 }
7670         }
7671         if (rsurface.texture->materialshaderpass)
7672         {
7673                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7674                 {
7675                 default:
7676                 case Q3TCGEN_TEXTURE:
7677                         break;
7678                 case Q3TCGEN_LIGHTMAP:
7679                         if (!dynamicvertex)
7680                         {
7681                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7682                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7683                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7684                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7685                         }
7686                         dynamicvertex = true;
7687                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7688                         break;
7689                 case Q3TCGEN_VECTOR:
7690                         if (!dynamicvertex)
7691                         {
7692                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7693                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7694                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7695                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7696                         }
7697                         dynamicvertex = true;
7698                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7699                         break;
7700                 case Q3TCGEN_ENVIRONMENT:
7701                         if (!dynamicvertex)
7702                         {
7703                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7704                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7705                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7706                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7707                         }
7708                         dynamicvertex = true;
7709                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7710                         break;
7711                 }
7712                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7713                 {
7714                         if (!dynamicvertex)
7715                         {
7716                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7717                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7718                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7719                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7720                         }
7721                         dynamicvertex = true;
7722                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7723                 }
7724         }
7725
7726         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7727         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7728         // we ensure this by treating the vertex batch as dynamic...
7729         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7730         {
7731                 if (!dynamicvertex)
7732                 {
7733                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7734                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7735                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7736                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7737                 }
7738                 dynamicvertex = true;
7739         }
7740
7741         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7742         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7743                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7744
7745         rsurface.batchvertex3f = rsurface.modelvertex3f;
7746         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7747         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7748         rsurface.batchsvector3f = rsurface.modelsvector3f;
7749         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7750         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7751         rsurface.batchtvector3f = rsurface.modeltvector3f;
7752         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7753         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7754         rsurface.batchnormal3f = rsurface.modelnormal3f;
7755         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7756         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7757         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7758         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7759         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7760         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7761         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7762         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7763         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7764         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7765         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7766         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7767         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7768         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7769         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7770         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7771         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7772         rsurface.batchelement3i = rsurface.modelelement3i;
7773         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7774         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7775         rsurface.batchelement3s = rsurface.modelelement3s;
7776         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7777         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7778         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7779         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7780         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7781         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7782         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7783
7784         // if any dynamic vertex processing has to occur in software, we copy the
7785         // entire surface list together before processing to rebase the vertices
7786         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7787         //
7788         // if any gaps exist and we do not have a static vertex buffer, we have to
7789         // copy the surface list together to avoid wasting upload bandwidth on the
7790         // vertices in the gaps.
7791         //
7792         // if gaps exist and we have a static vertex buffer, we can choose whether
7793         // to combine the index buffer ranges into one dynamic index buffer or
7794         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7795         //
7796         // in many cases the batch is reduced to one draw call.
7797
7798         rsurface.batchmultidraw = false;
7799         rsurface.batchmultidrawnumsurfaces = 0;
7800         rsurface.batchmultidrawsurfacelist = NULL;
7801
7802         if (!dynamicvertex)
7803         {
7804                 // static vertex data, just set pointers...
7805                 rsurface.batchgeneratedvertex = false;
7806                 // if there are gaps, we want to build a combined index buffer,
7807                 // otherwise use the original static buffer with an appropriate offset
7808                 if (gaps)
7809                 {
7810                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7811                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7812                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7813                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7814                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7815                         {
7816                                 rsurface.batchmultidraw = true;
7817                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7818                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7819                                 return;
7820                         }
7821                         // build a new triangle elements array for this batch
7822                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7823                         rsurface.batchfirsttriangle = 0;
7824                         numtriangles = 0;
7825                         for (i = 0;i < texturenumsurfaces;i++)
7826                         {
7827                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7828                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7829                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7830                                 numtriangles += surfacenumtriangles;
7831                         }
7832                         rsurface.batchelement3i_indexbuffer = NULL;
7833                         rsurface.batchelement3i_bufferoffset = 0;
7834                         rsurface.batchelement3s = NULL;
7835                         rsurface.batchelement3s_indexbuffer = NULL;
7836                         rsurface.batchelement3s_bufferoffset = 0;
7837                         if (endvertex <= 65536)
7838                         {
7839                                 // make a 16bit (unsigned short) index array if possible
7840                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7841                                 for (i = 0;i < numtriangles*3;i++)
7842                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7843                         }
7844                 }
7845                 else
7846                 {
7847                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7848                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7849                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7850                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7851                 }
7852                 return;
7853         }
7854
7855         // something needs software processing, do it for real...
7856         // we only directly handle separate array data in this case and then
7857         // generate interleaved data if needed...
7858         rsurface.batchgeneratedvertex = true;
7859         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7860         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7861         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7862         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7863
7864         // now copy the vertex data into a combined array and make an index array
7865         // (this is what Quake3 does all the time)
7866         // we also apply any skeletal animation here that would have been done in
7867         // the vertex shader, because most of the dynamic vertex animation cases
7868         // need actual vertex positions and normals
7869         //if (dynamicvertex)
7870         {
7871                 rsurface.batchvertex3f = NULL;
7872                 rsurface.batchvertex3f_vertexbuffer = NULL;
7873                 rsurface.batchvertex3f_bufferoffset = 0;
7874                 rsurface.batchsvector3f = NULL;
7875                 rsurface.batchsvector3f_vertexbuffer = NULL;
7876                 rsurface.batchsvector3f_bufferoffset = 0;
7877                 rsurface.batchtvector3f = NULL;
7878                 rsurface.batchtvector3f_vertexbuffer = NULL;
7879                 rsurface.batchtvector3f_bufferoffset = 0;
7880                 rsurface.batchnormal3f = NULL;
7881                 rsurface.batchnormal3f_vertexbuffer = NULL;
7882                 rsurface.batchnormal3f_bufferoffset = 0;
7883                 rsurface.batchlightmapcolor4f = NULL;
7884                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7885                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7886                 rsurface.batchtexcoordtexture2f = NULL;
7887                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7888                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7889                 rsurface.batchtexcoordlightmap2f = NULL;
7890                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7891                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7892                 rsurface.batchskeletalindex4ub = NULL;
7893                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7894                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7895                 rsurface.batchskeletalweight4ub = NULL;
7896                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7897                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7898                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7899                 rsurface.batchelement3i_indexbuffer = NULL;
7900                 rsurface.batchelement3i_bufferoffset = 0;
7901                 rsurface.batchelement3s = NULL;
7902                 rsurface.batchelement3s_indexbuffer = NULL;
7903                 rsurface.batchelement3s_bufferoffset = 0;
7904                 rsurface.batchskeletaltransform3x4buffer = NULL;
7905                 rsurface.batchskeletaltransform3x4offset = 0;
7906                 rsurface.batchskeletaltransform3x4size = 0;
7907                 // we'll only be setting up certain arrays as needed
7908                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7909                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7910                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7911                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7912                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7913                 {
7914                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7915                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7916                 }
7917                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7918                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7919                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7920                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7921                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7922                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7923                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7924                 {
7925                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7926                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7927                 }
7928                 numvertices = 0;
7929                 numtriangles = 0;
7930                 for (i = 0;i < texturenumsurfaces;i++)
7931                 {
7932                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7933                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7934                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7935                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7936                         // copy only the data requested
7937                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7938                         {
7939                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7940                                 {
7941                                         if (rsurface.batchvertex3f)
7942                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7943                                         else
7944                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7945                                 }
7946                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7947                                 {
7948                                         if (rsurface.modelnormal3f)
7949                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7950                                         else
7951                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7952                                 }
7953                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7954                                 {
7955                                         if (rsurface.modelsvector3f)
7956                                         {
7957                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7958                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7959                                         }
7960                                         else
7961                                         {
7962                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7963                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7964                                         }
7965                                 }
7966                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7967                                 {
7968                                         if (rsurface.modellightmapcolor4f)
7969                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7970                                         else
7971                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7972                                 }
7973                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7974                                 {
7975                                         if (rsurface.modeltexcoordtexture2f)
7976                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7977                                         else
7978                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7979                                 }
7980                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7981                                 {
7982                                         if (rsurface.modeltexcoordlightmap2f)
7983                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7984                                         else
7985                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7986                                 }
7987                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7988                                 {
7989                                         if (rsurface.modelskeletalindex4ub)
7990                                         {
7991                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7992                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7993                                         }
7994                                         else
7995                                         {
7996                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7997                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7998                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7999                                                 for (j = 0;j < surfacenumvertices;j++)
8000                                                         ub[j*4] = 255;
8001                                         }
8002                                 }
8003                         }
8004                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8005                         numvertices += surfacenumvertices;
8006                         numtriangles += surfacenumtriangles;
8007                 }
8008
8009                 // generate a 16bit index array as well if possible
8010                 // (in general, dynamic batches fit)
8011                 if (numvertices <= 65536)
8012                 {
8013                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8014                         for (i = 0;i < numtriangles*3;i++)
8015                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8016                 }
8017
8018                 // since we've copied everything, the batch now starts at 0
8019                 rsurface.batchfirstvertex = 0;
8020                 rsurface.batchnumvertices = batchnumvertices;
8021                 rsurface.batchfirsttriangle = 0;
8022                 rsurface.batchnumtriangles = batchnumtriangles;
8023         }
8024
8025         // apply skeletal animation that would have been done in the vertex shader
8026         if (rsurface.batchskeletaltransform3x4)
8027         {
8028                 const unsigned char *si;
8029                 const unsigned char *sw;
8030                 const float *t[4];
8031                 const float *b = rsurface.batchskeletaltransform3x4;
8032                 float *vp, *vs, *vt, *vn;
8033                 float w[4];
8034                 float m[3][4], n[3][4];
8035                 float tp[3], ts[3], tt[3], tn[3];
8036                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8037                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8038                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8039                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8040                 si = rsurface.batchskeletalindex4ub;
8041                 sw = rsurface.batchskeletalweight4ub;
8042                 vp = rsurface.batchvertex3f;
8043                 vs = rsurface.batchsvector3f;
8044                 vt = rsurface.batchtvector3f;
8045                 vn = rsurface.batchnormal3f;
8046                 memset(m[0], 0, sizeof(m));
8047                 memset(n[0], 0, sizeof(n));
8048                 for (i = 0;i < batchnumvertices;i++)
8049                 {
8050                         t[0] = b + si[0]*12;
8051                         if (sw[0] == 255)
8052                         {
8053                                 // common case - only one matrix
8054                                 m[0][0] = t[0][ 0];
8055                                 m[0][1] = t[0][ 1];
8056                                 m[0][2] = t[0][ 2];
8057                                 m[0][3] = t[0][ 3];
8058                                 m[1][0] = t[0][ 4];
8059                                 m[1][1] = t[0][ 5];
8060                                 m[1][2] = t[0][ 6];
8061                                 m[1][3] = t[0][ 7];
8062                                 m[2][0] = t[0][ 8];
8063                                 m[2][1] = t[0][ 9];
8064                                 m[2][2] = t[0][10];
8065                                 m[2][3] = t[0][11];
8066                         }
8067                         else if (sw[2] + sw[3])
8068                         {
8069                                 // blend 4 matrices
8070                                 t[1] = b + si[1]*12;
8071                                 t[2] = b + si[2]*12;
8072                                 t[3] = b + si[3]*12;
8073                                 w[0] = sw[0] * (1.0f / 255.0f);
8074                                 w[1] = sw[1] * (1.0f / 255.0f);
8075                                 w[2] = sw[2] * (1.0f / 255.0f);
8076                                 w[3] = sw[3] * (1.0f / 255.0f);
8077                                 // blend the matrices
8078                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8079                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8080                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8081                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8082                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8083                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8084                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8085                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8086                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8087                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8088                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8089                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8090                         }
8091                         else
8092                         {
8093                                 // blend 2 matrices
8094                                 t[1] = b + si[1]*12;
8095                                 w[0] = sw[0] * (1.0f / 255.0f);
8096                                 w[1] = sw[1] * (1.0f / 255.0f);
8097                                 // blend the matrices
8098                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8099                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8100                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8101                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8102                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8103                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8104                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8105                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8106                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8107                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8108                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8109                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8110                         }
8111                         si += 4;
8112                         sw += 4;
8113                         // modify the vertex
8114                         VectorCopy(vp, tp);
8115                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8116                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8117                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8118                         vp += 3;
8119                         if (vn)
8120                         {
8121                                 // the normal transformation matrix is a set of cross products...
8122                                 CrossProduct(m[1], m[2], n[0]);
8123                                 CrossProduct(m[2], m[0], n[1]);
8124                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8125                                 VectorCopy(vn, tn);
8126                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8127                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8128                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8129                                 VectorNormalize(vn);
8130                                 vn += 3;
8131                                 if (vs)
8132                                 {
8133                                         VectorCopy(vs, ts);
8134                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8135                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8136                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8137                                         VectorNormalize(vs);
8138                                         vs += 3;
8139                                         VectorCopy(vt, tt);
8140                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8141                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8142                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8143                                         VectorNormalize(vt);
8144                                         vt += 3;
8145                                 }
8146                         }
8147                 }
8148                 rsurface.batchskeletaltransform3x4 = NULL;
8149                 rsurface.batchskeletalnumtransforms = 0;
8150         }
8151
8152         // q1bsp surfaces rendered in vertex color mode have to have colors
8153         // calculated based on lightstyles
8154         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8155         {
8156                 // generate color arrays for the surfaces in this list
8157                 int c[4];
8158                 int scale;
8159                 int size3;
8160                 const int *offsets;
8161                 const unsigned char *lm;
8162                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8163                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8164                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8165                 numvertices = 0;
8166                 for (i = 0;i < texturenumsurfaces;i++)
8167                 {
8168                         surface = texturesurfacelist[i];
8169                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8170                         surfacenumvertices = surface->num_vertices;
8171                         if (surface->lightmapinfo->samples)
8172                         {
8173                                 for (j = 0;j < surfacenumvertices;j++)
8174                                 {
8175                                         lm = surface->lightmapinfo->samples + offsets[j];
8176                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8177                                         VectorScale(lm, scale, c);
8178                                         if (surface->lightmapinfo->styles[1] != 255)
8179                                         {
8180                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8181                                                 lm += size3;
8182                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8183                                                 VectorMA(c, scale, lm, c);
8184                                                 if (surface->lightmapinfo->styles[2] != 255)
8185                                                 {
8186                                                         lm += size3;
8187                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8188                                                         VectorMA(c, scale, lm, c);
8189                                                         if (surface->lightmapinfo->styles[3] != 255)
8190                                                         {
8191                                                                 lm += size3;
8192                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8193                                                                 VectorMA(c, scale, lm, c);
8194                                                         }
8195                                                 }
8196                                         }
8197                                         c[0] >>= 7;
8198                                         c[1] >>= 7;
8199                                         c[2] >>= 7;
8200                                         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);
8201                                         numvertices++;
8202                                 }
8203                         }
8204                         else
8205                         {
8206                                 for (j = 0;j < surfacenumvertices;j++)
8207                                 {
8208                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8209                                         numvertices++;
8210                                 }
8211                         }
8212                 }
8213         }
8214
8215         // if vertices are deformed (sprite flares and things in maps, possibly
8216         // water waves, bulges and other deformations), modify the copied vertices
8217         // in place
8218         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8219         {
8220                 float scale;
8221                 switch (deform->deform)
8222                 {
8223                 default:
8224                 case Q3DEFORM_PROJECTIONSHADOW:
8225                 case Q3DEFORM_TEXT0:
8226                 case Q3DEFORM_TEXT1:
8227                 case Q3DEFORM_TEXT2:
8228                 case Q3DEFORM_TEXT3:
8229                 case Q3DEFORM_TEXT4:
8230                 case Q3DEFORM_TEXT5:
8231                 case Q3DEFORM_TEXT6:
8232                 case Q3DEFORM_TEXT7:
8233                 case Q3DEFORM_NONE:
8234                         break;
8235                 case Q3DEFORM_AUTOSPRITE:
8236                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8237                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8238                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8239                         VectorNormalize(newforward);
8240                         VectorNormalize(newright);
8241                         VectorNormalize(newup);
8242 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8243 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8244 //                      rsurface.batchvertex3f_bufferoffset = 0;
8245 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8246 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8247 //                      rsurface.batchsvector3f_bufferoffset = 0;
8248 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8249 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8250 //                      rsurface.batchtvector3f_bufferoffset = 0;
8251 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8252 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8253 //                      rsurface.batchnormal3f_bufferoffset = 0;
8254                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8255                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8256                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8257                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8258                                 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);
8259                         // a single autosprite surface can contain multiple sprites...
8260                         for (j = 0;j < batchnumvertices - 3;j += 4)
8261                         {
8262                                 VectorClear(center);
8263                                 for (i = 0;i < 4;i++)
8264                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8265                                 VectorScale(center, 0.25f, center);
8266                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8267                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8268                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8269                                 for (i = 0;i < 4;i++)
8270                                 {
8271                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8272                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8273                                 }
8274                         }
8275                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8276                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8277                         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);
8278                         break;
8279                 case Q3DEFORM_AUTOSPRITE2:
8280                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8281                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8282                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8283                         VectorNormalize(newforward);
8284                         VectorNormalize(newright);
8285                         VectorNormalize(newup);
8286 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8287 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8288 //                      rsurface.batchvertex3f_bufferoffset = 0;
8289                         {
8290                                 const float *v1, *v2;
8291                                 vec3_t start, end;
8292                                 float f, l;
8293                                 struct
8294                                 {
8295                                         float length2;
8296                                         const float *v1;
8297                                         const float *v2;
8298                                 }
8299                                 shortest[2];
8300                                 memset(shortest, 0, sizeof(shortest));
8301                                 // a single autosprite surface can contain multiple sprites...
8302                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8303                                 {
8304                                         VectorClear(center);
8305                                         for (i = 0;i < 4;i++)
8306                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8307                                         VectorScale(center, 0.25f, center);
8308                                         // find the two shortest edges, then use them to define the
8309                                         // axis vectors for rotating around the central axis
8310                                         for (i = 0;i < 6;i++)
8311                                         {
8312                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8313                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8314                                                 l = VectorDistance2(v1, v2);
8315                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8316                                                 if (v1[2] != v2[2])
8317                                                         l += (1.0f / 1024.0f);
8318                                                 if (shortest[0].length2 > l || i == 0)
8319                                                 {
8320                                                         shortest[1] = shortest[0];
8321                                                         shortest[0].length2 = l;
8322                                                         shortest[0].v1 = v1;
8323                                                         shortest[0].v2 = v2;
8324                                                 }
8325                                                 else if (shortest[1].length2 > l || i == 1)
8326                                                 {
8327                                                         shortest[1].length2 = l;
8328                                                         shortest[1].v1 = v1;
8329                                                         shortest[1].v2 = v2;
8330                                                 }
8331                                         }
8332                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8333                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8334                                         // this calculates the right vector from the shortest edge
8335                                         // and the up vector from the edge midpoints
8336                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8337                                         VectorNormalize(right);
8338                                         VectorSubtract(end, start, up);
8339                                         VectorNormalize(up);
8340                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8341                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8342                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8343                                         VectorNegate(forward, forward);
8344                                         VectorReflect(forward, 0, up, forward);
8345                                         VectorNormalize(forward);
8346                                         CrossProduct(up, forward, newright);
8347                                         VectorNormalize(newright);
8348                                         // rotate the quad around the up axis vector, this is made
8349                                         // especially easy by the fact we know the quad is flat,
8350                                         // so we only have to subtract the center position and
8351                                         // measure distance along the right vector, and then
8352                                         // multiply that by the newright vector and add back the
8353                                         // center position
8354                                         // we also need to subtract the old position to undo the
8355                                         // displacement from the center, which we do with a
8356                                         // DotProduct, the subtraction/addition of center is also
8357                                         // optimized into DotProducts here
8358                                         l = DotProduct(right, center);
8359                                         for (i = 0;i < 4;i++)
8360                                         {
8361                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8362                                                 f = DotProduct(right, v1) - l;
8363                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8364                                         }
8365                                 }
8366                         }
8367                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8368                         {
8369 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8370 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8371 //                              rsurface.batchnormal3f_bufferoffset = 0;
8372                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8373                         }
8374                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8375                         {
8376 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8377 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8378 //                              rsurface.batchsvector3f_bufferoffset = 0;
8379 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8380 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8381 //                              rsurface.batchtvector3f_bufferoffset = 0;
8382                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8383                         }
8384                         break;
8385                 case Q3DEFORM_NORMAL:
8386                         // deform the normals to make reflections wavey
8387                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8388                         rsurface.batchnormal3f_vertexbuffer = NULL;
8389                         rsurface.batchnormal3f_bufferoffset = 0;
8390                         for (j = 0;j < batchnumvertices;j++)
8391                         {
8392                                 float vertex[3];
8393                                 float *normal = rsurface.batchnormal3f + 3*j;
8394                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8395                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8396                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8397                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8398                                 VectorNormalize(normal);
8399                         }
8400                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8401                         {
8402 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8403 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8404 //                              rsurface.batchsvector3f_bufferoffset = 0;
8405 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8406 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8407 //                              rsurface.batchtvector3f_bufferoffset = 0;
8408                                 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);
8409                         }
8410                         break;
8411                 case Q3DEFORM_WAVE:
8412                         // deform vertex array to make wavey water and flags and such
8413                         waveparms[0] = deform->waveparms[0];
8414                         waveparms[1] = deform->waveparms[1];
8415                         waveparms[2] = deform->waveparms[2];
8416                         waveparms[3] = deform->waveparms[3];
8417                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8418                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8419                         // this is how a divisor of vertex influence on deformation
8420                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8421                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8422 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8423 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8424 //                      rsurface.batchvertex3f_bufferoffset = 0;
8425 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8426 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8427 //                      rsurface.batchnormal3f_bufferoffset = 0;
8428                         for (j = 0;j < batchnumvertices;j++)
8429                         {
8430                                 // if the wavefunc depends on time, evaluate it per-vertex
8431                                 if (waveparms[3])
8432                                 {
8433                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8434                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8435                                 }
8436                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8437                         }
8438                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8439                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8440                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8441                         {
8442 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8443 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8444 //                              rsurface.batchsvector3f_bufferoffset = 0;
8445 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8446 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8447 //                              rsurface.batchtvector3f_bufferoffset = 0;
8448                                 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);
8449                         }
8450                         break;
8451                 case Q3DEFORM_BULGE:
8452                         // deform vertex array to make the surface have moving bulges
8453 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8454 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8455 //                      rsurface.batchvertex3f_bufferoffset = 0;
8456 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8457 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8458 //                      rsurface.batchnormal3f_bufferoffset = 0;
8459                         for (j = 0;j < batchnumvertices;j++)
8460                         {
8461                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8462                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8463                         }
8464                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8465                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8466                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8467                         {
8468 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8469 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8470 //                              rsurface.batchsvector3f_bufferoffset = 0;
8471 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8472 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8473 //                              rsurface.batchtvector3f_bufferoffset = 0;
8474                                 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);
8475                         }
8476                         break;
8477                 case Q3DEFORM_MOVE:
8478                         // deform vertex array
8479                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8480                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8481                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8482                         VectorScale(deform->parms, scale, waveparms);
8483 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8484 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8485 //                      rsurface.batchvertex3f_bufferoffset = 0;
8486                         for (j = 0;j < batchnumvertices;j++)
8487                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8488                         break;
8489                 }
8490         }
8491
8492         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8493         {
8494         // generate texcoords based on the chosen texcoord source
8495                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8496                 {
8497                 default:
8498                 case Q3TCGEN_TEXTURE:
8499                         break;
8500                 case Q3TCGEN_LIGHTMAP:
8501         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8502         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8503         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8504                         if (rsurface.batchtexcoordlightmap2f)
8505                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8506                         break;
8507                 case Q3TCGEN_VECTOR:
8508         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8509         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8510         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8511                         for (j = 0;j < batchnumvertices;j++)
8512                         {
8513                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8514                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8515                         }
8516                         break;
8517                 case Q3TCGEN_ENVIRONMENT:
8518                         // make environment reflections using a spheremap
8519                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8520                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8521                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8522                         for (j = 0;j < batchnumvertices;j++)
8523                         {
8524                                 // identical to Q3A's method, but executed in worldspace so
8525                                 // carried models can be shiny too
8526
8527                                 float viewer[3], d, reflected[3], worldreflected[3];
8528
8529                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8530                                 // VectorNormalize(viewer);
8531
8532                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8533
8534                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8535                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8536                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8537                                 // note: this is proportinal to viewer, so we can normalize later
8538
8539                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8540                                 VectorNormalize(worldreflected);
8541
8542                                 // note: this sphere map only uses world x and z!
8543                                 // so positive and negative y will LOOK THE SAME.
8544                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8545                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8546                         }
8547                         break;
8548                 }
8549                 // the only tcmod that needs software vertex processing is turbulent, so
8550                 // check for it here and apply the changes if needed
8551                 // and we only support that as the first one
8552                 // (handling a mixture of turbulent and other tcmods would be problematic
8553                 //  without punting it entirely to a software path)
8554                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8555                 {
8556                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8557                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8558         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8559         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8560         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8561                         for (j = 0;j < batchnumvertices;j++)
8562                         {
8563                                 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);
8564                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8565                         }
8566                 }
8567         }
8568 }
8569
8570 void RSurf_DrawBatch(void)
8571 {
8572         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8573         // through the pipeline, killing it earlier in the pipeline would have
8574         // per-surface overhead rather than per-batch overhead, so it's best to
8575         // reject it here, before it hits glDraw.
8576         if (rsurface.batchnumtriangles == 0)
8577                 return;
8578 #if 0
8579         // batch debugging code
8580         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8581         {
8582                 int i;
8583                 int j;
8584                 int c;
8585                 const int *e;
8586                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8587                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8588                 {
8589                         c = e[i];
8590                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8591                         {
8592                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8593                                 {
8594                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8595                                                 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);
8596                                         break;
8597                                 }
8598                         }
8599                 }
8600         }
8601 #endif
8602         if (rsurface.batchmultidraw)
8603         {
8604                 // issue multiple draws rather than copying index data
8605                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8606                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8607                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8608                 for (i = 0;i < numsurfaces;)
8609                 {
8610                         // combine consecutive surfaces as one draw
8611                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8612                                 if (surfacelist[j] != surfacelist[k] + 1)
8613                                         break;
8614                         firstvertex = surfacelist[i]->num_firstvertex;
8615                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8616                         firsttriangle = surfacelist[i]->num_firsttriangle;
8617                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8618                         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);
8619                         i = j;
8620                 }
8621         }
8622         else
8623         {
8624                 // there is only one consecutive run of index data (may have been combined)
8625                 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);
8626         }
8627 }
8628
8629 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8630 {
8631         // pick the closest matching water plane
8632         int planeindex, vertexindex, bestplaneindex = -1;
8633         float d, bestd;
8634         vec3_t vert;
8635         const float *v;
8636         r_waterstate_waterplane_t *p;
8637         qboolean prepared = false;
8638         bestd = 0;
8639         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8640         {
8641                 if(p->camera_entity != rsurface.texture->camera_entity)
8642                         continue;
8643                 d = 0;
8644                 if(!prepared)
8645                 {
8646                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8647                         prepared = true;
8648                         if(rsurface.batchnumvertices == 0)
8649                                 break;
8650                 }
8651                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8652                 {
8653                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8654                         d += fabs(PlaneDiff(vert, &p->plane));
8655                 }
8656                 if (bestd > d || bestplaneindex < 0)
8657                 {
8658                         bestd = d;
8659                         bestplaneindex = planeindex;
8660                 }
8661         }
8662         return bestplaneindex;
8663         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8664         // this situation though, as it might be better to render single larger
8665         // batches with useless stuff (backface culled for example) than to
8666         // render multiple smaller batches
8667 }
8668
8669 void RSurf_SetupDepthAndCulling(void)
8670 {
8671         // submodels are biased to avoid z-fighting with world surfaces that they
8672         // may be exactly overlapping (avoids z-fighting artifacts on certain
8673         // doors and things in Quake maps)
8674         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8675         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8676         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8677         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8678 }
8679
8680 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8681 {
8682         int j;
8683         const float *v;
8684         float p[3], mins[3], maxs[3];
8685         int scissor[4];
8686         // transparent sky would be ridiculous
8687         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8688                 return;
8689         R_SetupShader_Generic_NoTexture(false, false);
8690         skyrenderlater = true;
8691         RSurf_SetupDepthAndCulling();
8692         GL_DepthMask(true);
8693
8694         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8695         if (r_sky_scissor.integer)
8696         {
8697                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8698                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8699                 {
8700                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8701                         if (j > 0)
8702                         {
8703                                 if (mins[0] > p[0]) mins[0] = p[0];
8704                                 if (mins[1] > p[1]) mins[1] = p[1];
8705                                 if (mins[2] > p[2]) mins[2] = p[2];
8706                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8707                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8708                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8709                         }
8710                         else
8711                         {
8712                                 VectorCopy(p, mins);
8713                                 VectorCopy(p, maxs);
8714                         }
8715                 }
8716                 if (!R_ScissorForBBox(mins, maxs, scissor))
8717                 {
8718                         if (skyscissor[2])
8719                         {
8720                                 if (skyscissor[0] > scissor[0])
8721                                 {
8722                                         skyscissor[2] += skyscissor[0] - scissor[0];
8723                                         skyscissor[0] = scissor[0];
8724                                 }
8725                                 if (skyscissor[1] > scissor[1])
8726                                 {
8727                                         skyscissor[3] += skyscissor[1] - scissor[1];
8728                                         skyscissor[1] = scissor[1];
8729                                 }
8730                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8731                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8732                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8733                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8734                         }
8735                         else
8736                                 Vector4Copy(scissor, skyscissor);
8737                 }
8738         }
8739
8740         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8741         // skymasking on them, and Quake3 never did sky masking (unlike
8742         // software Quake and software Quake2), so disable the sky masking
8743         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8744         // and skymasking also looks very bad when noclipping outside the
8745         // level, so don't use it then either.
8746         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)
8747         {
8748                 R_Mesh_ResetTextureState();
8749                 if (skyrendermasked)
8750                 {
8751                         R_SetupShader_DepthOrShadow(false, false, false);
8752                         // depth-only (masking)
8753                         GL_ColorMask(0, 0, 0, 0);
8754                         // just to make sure that braindead drivers don't draw
8755                         // anything despite that colormask...
8756                         GL_BlendFunc(GL_ZERO, GL_ONE);
8757                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8758                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8759                 }
8760                 else
8761                 {
8762                         R_SetupShader_Generic_NoTexture(false, false);
8763                         // fog sky
8764                         GL_BlendFunc(GL_ONE, GL_ZERO);
8765                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8766                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8767                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8768                 }
8769                 RSurf_DrawBatch();
8770                 if (skyrendermasked)
8771                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8772         }
8773         R_Mesh_ResetTextureState();
8774         GL_Color(1, 1, 1, 1);
8775 }
8776
8777 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8778 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8779 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8780 {
8781         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8782                 return;
8783         if (prepass)
8784         {
8785                 // render screenspace normalmap to texture
8786                 GL_DepthMask(true);
8787                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8788                 RSurf_DrawBatch();
8789                 return;
8790         }
8791
8792         // bind lightmap texture
8793
8794         // water/refraction/reflection/camera surfaces have to be handled specially
8795         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8796         {
8797                 int start, end, startplaneindex;
8798                 for (start = 0;start < texturenumsurfaces;start = end)
8799                 {
8800                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8801                         if(startplaneindex < 0)
8802                         {
8803                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8804                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8805                                 end = start + 1;
8806                                 continue;
8807                         }
8808                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8809                                 ;
8810                         // now that we have a batch using the same planeindex, render it
8811                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8812                         {
8813                                 // render water or distortion background
8814                                 GL_DepthMask(true);
8815                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8816                                 RSurf_DrawBatch();
8817                                 // blend surface on top
8818                                 GL_DepthMask(false);
8819                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8820                                 RSurf_DrawBatch();
8821                         }
8822                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8823                         {
8824                                 // render surface with reflection texture as input
8825                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8826                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8827                                 RSurf_DrawBatch();
8828                         }
8829                 }
8830                 return;
8831         }
8832
8833         // render surface batch normally
8834         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8835         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8836         RSurf_DrawBatch();
8837 }
8838
8839 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8840 {
8841         int vi;
8842         int j;
8843         int texturesurfaceindex;
8844         int k;
8845         const msurface_t *surface;
8846         float surfacecolor4f[4];
8847
8848 //      R_Mesh_ResetTextureState();
8849         R_SetupShader_Generic_NoTexture(false, false);
8850
8851         GL_BlendFunc(GL_ONE, GL_ZERO);
8852         GL_DepthMask(writedepth);
8853
8854         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8855         vi = 0;
8856         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8857         {
8858                 surface = texturesurfacelist[texturesurfaceindex];
8859                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8860                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8861                 for (j = 0;j < surface->num_vertices;j++)
8862                 {
8863                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8864                         vi++;
8865                 }
8866         }
8867         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8868         RSurf_DrawBatch();
8869 }
8870
8871 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8872 {
8873         CHECKGLERROR
8874         RSurf_SetupDepthAndCulling();
8875         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8876         {
8877                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8878                 return;
8879         }
8880         switch (vid.renderpath)
8881         {
8882         case RENDERPATH_GL32:
8883         case RENDERPATH_GLES2:
8884                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8885                 break;
8886         }
8887         CHECKGLERROR
8888 }
8889
8890 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8891 {
8892         int i, j;
8893         int texturenumsurfaces, endsurface;
8894         texture_t *texture;
8895         const msurface_t *surface;
8896         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8897
8898         RSurf_ActiveModelEntity(ent, true, true, false);
8899
8900         if (r_transparentdepthmasking.integer)
8901         {
8902                 qboolean setup = false;
8903                 for (i = 0;i < numsurfaces;i = j)
8904                 {
8905                         j = i + 1;
8906                         surface = rsurface.modelsurfaces + surfacelist[i];
8907                         texture = surface->texture;
8908                         rsurface.texture = R_GetCurrentTexture(texture);
8909                         rsurface.lightmaptexture = NULL;
8910                         rsurface.deluxemaptexture = NULL;
8911                         rsurface.uselightmaptexture = false;
8912                         // scan ahead until we find a different texture
8913                         endsurface = min(i + 1024, numsurfaces);
8914                         texturenumsurfaces = 0;
8915                         texturesurfacelist[texturenumsurfaces++] = surface;
8916                         for (;j < endsurface;j++)
8917                         {
8918                                 surface = rsurface.modelsurfaces + surfacelist[j];
8919                                 if (texture != surface->texture)
8920                                         break;
8921                                 texturesurfacelist[texturenumsurfaces++] = surface;
8922                         }
8923                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8924                                 continue;
8925                         // render the range of surfaces as depth
8926                         if (!setup)
8927                         {
8928                                 setup = true;
8929                                 GL_ColorMask(0,0,0,0);
8930                                 GL_Color(1,1,1,1);
8931                                 GL_DepthTest(true);
8932                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8933                                 GL_DepthMask(true);
8934 //                              R_Mesh_ResetTextureState();
8935                         }
8936                         RSurf_SetupDepthAndCulling();
8937                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8938                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8939                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8940                         RSurf_DrawBatch();
8941                 }
8942                 if (setup)
8943                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8944         }
8945
8946         for (i = 0;i < numsurfaces;i = j)
8947         {
8948                 j = i + 1;
8949                 surface = rsurface.modelsurfaces + surfacelist[i];
8950                 texture = surface->texture;
8951                 rsurface.texture = R_GetCurrentTexture(texture);
8952                 // scan ahead until we find a different texture
8953                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8954                 texturenumsurfaces = 0;
8955                 texturesurfacelist[texturenumsurfaces++] = surface;
8956                         rsurface.lightmaptexture = surface->lightmaptexture;
8957                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8958                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8959                         for (;j < endsurface;j++)
8960                         {
8961                                 surface = rsurface.modelsurfaces + surfacelist[j];
8962                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8963                                         break;
8964                                 texturesurfacelist[texturenumsurfaces++] = surface;
8965                         }
8966                 // render the range of surfaces
8967                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8968         }
8969         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8970 }
8971
8972 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8973 {
8974         // transparent surfaces get pushed off into the transparent queue
8975         int surfacelistindex;
8976         const msurface_t *surface;
8977         vec3_t tempcenter, center;
8978         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8979         {
8980                 surface = texturesurfacelist[surfacelistindex];
8981                 if (r_transparent_sortsurfacesbynearest.integer)
8982                 {
8983                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8984                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8985                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8986                 }
8987                 else
8988                 {
8989                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8990                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8991                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8992                 }
8993                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8994                 if (rsurface.entity->transparent_offset) // transparent offset
8995                 {
8996                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8997                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8998                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8999                 }
9000                 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);
9001         }
9002 }
9003
9004 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9005 {
9006         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9007                 return;
9008         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9009                 return;
9010         RSurf_SetupDepthAndCulling();
9011         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9012         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9013         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9014         RSurf_DrawBatch();
9015 }
9016
9017 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9018 {
9019         CHECKGLERROR
9020         if (ui)
9021                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9022         else if (depthonly)
9023                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9024         else if (prepass)
9025         {
9026                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9027                         return;
9028                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9029                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9030                 else
9031                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9032         }
9033         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9034                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9035         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9036                 return;
9037         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9038         {
9039                 // in the deferred case, transparent surfaces were queued during prepass
9040                 if (!r_shadow_usingdeferredprepass)
9041                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9042         }
9043         else
9044         {
9045                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9046                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9047         }
9048         CHECKGLERROR
9049 }
9050
9051 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9052 {
9053         int i, j;
9054         texture_t *texture;
9055         R_FrameData_SetMark();
9056         // break the surface list down into batches by texture and use of lightmapping
9057         for (i = 0;i < numsurfaces;i = j)
9058         {
9059                 j = i + 1;
9060                 // texture is the base texture pointer, rsurface.texture is the
9061                 // current frame/skin the texture is directing us to use (for example
9062                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9063                 // use skin 1 instead)
9064                 texture = surfacelist[i]->texture;
9065                 rsurface.texture = R_GetCurrentTexture(texture);
9066                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9067                 {
9068                         // if this texture is not the kind we want, skip ahead to the next one
9069                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9070                                 ;
9071                         continue;
9072                 }
9073                 if(depthonly || prepass)
9074                 {
9075                         rsurface.lightmaptexture = NULL;
9076                         rsurface.deluxemaptexture = NULL;
9077                         rsurface.uselightmaptexture = false;
9078                         // simply scan ahead until we find a different texture or lightmap state
9079                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9080                                 ;
9081                 }
9082                 else
9083                 {
9084                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9085                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9086                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9087                         // simply scan ahead until we find a different texture or lightmap state
9088                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9089                                 ;
9090                 }
9091                 // render the range of surfaces
9092                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9093         }
9094         R_FrameData_ReturnToMark();
9095 }
9096
9097 float locboxvertex3f[6*4*3] =
9098 {
9099         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9100         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9101         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9102         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9103         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9104         1,0,0, 0,0,0, 0,1,0, 1,1,0
9105 };
9106
9107 unsigned short locboxelements[6*2*3] =
9108 {
9109          0, 1, 2, 0, 2, 3,
9110          4, 5, 6, 4, 6, 7,
9111          8, 9,10, 8,10,11,
9112         12,13,14, 12,14,15,
9113         16,17,18, 16,18,19,
9114         20,21,22, 20,22,23
9115 };
9116
9117 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9118 {
9119         int i, j;
9120         cl_locnode_t *loc = (cl_locnode_t *)ent;
9121         vec3_t mins, size;
9122         float vertex3f[6*4*3];
9123         CHECKGLERROR
9124         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9125         GL_DepthMask(false);
9126         GL_DepthRange(0, 1);
9127         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9128         GL_DepthTest(true);
9129         GL_CullFace(GL_NONE);
9130         R_EntityMatrix(&identitymatrix);
9131
9132 //      R_Mesh_ResetTextureState();
9133
9134         i = surfacelist[0];
9135         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9136                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9137                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9138                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9139
9140         if (VectorCompare(loc->mins, loc->maxs))
9141         {
9142                 VectorSet(size, 2, 2, 2);
9143                 VectorMA(loc->mins, -0.5f, size, mins);
9144         }
9145         else
9146         {
9147                 VectorCopy(loc->mins, mins);
9148                 VectorSubtract(loc->maxs, loc->mins, size);
9149         }
9150
9151         for (i = 0;i < 6*4*3;)
9152                 for (j = 0;j < 3;j++, i++)
9153                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9154
9155         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9156         R_SetupShader_Generic_NoTexture(false, false);
9157         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9158 }
9159
9160 void R_DrawLocs(void)
9161 {
9162         int index;
9163         cl_locnode_t *loc, *nearestloc;
9164         vec3_t center;
9165         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9166         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9167         {
9168                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9169                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9170         }
9171 }
9172
9173 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9174 {
9175         if (decalsystem->decals)
9176                 Mem_Free(decalsystem->decals);
9177         memset(decalsystem, 0, sizeof(*decalsystem));
9178 }
9179
9180 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)
9181 {
9182         tridecal_t *decal;
9183         tridecal_t *decals;
9184         int i;
9185
9186         // expand or initialize the system
9187         if (decalsystem->maxdecals <= decalsystem->numdecals)
9188         {
9189                 decalsystem_t old = *decalsystem;
9190                 qboolean useshortelements;
9191                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9192                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9193                 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)));
9194                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9195                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9196                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9197                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9198                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9199                 if (decalsystem->numdecals)
9200                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9201                 if (old.decals)
9202                         Mem_Free(old.decals);
9203                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9204                         decalsystem->element3i[i] = i;
9205                 if (useshortelements)
9206                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9207                                 decalsystem->element3s[i] = i;
9208         }
9209
9210         // grab a decal and search for another free slot for the next one
9211         decals = decalsystem->decals;
9212         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9213         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9214                 ;
9215         decalsystem->freedecal = i;
9216         if (decalsystem->numdecals <= i)
9217                 decalsystem->numdecals = i + 1;
9218
9219         // initialize the decal
9220         decal->lived = 0;
9221         decal->triangleindex = triangleindex;
9222         decal->surfaceindex = surfaceindex;
9223         decal->decalsequence = decalsequence;
9224         decal->color4f[0][0] = c0[0];
9225         decal->color4f[0][1] = c0[1];
9226         decal->color4f[0][2] = c0[2];
9227         decal->color4f[0][3] = 1;
9228         decal->color4f[1][0] = c1[0];
9229         decal->color4f[1][1] = c1[1];
9230         decal->color4f[1][2] = c1[2];
9231         decal->color4f[1][3] = 1;
9232         decal->color4f[2][0] = c2[0];
9233         decal->color4f[2][1] = c2[1];
9234         decal->color4f[2][2] = c2[2];
9235         decal->color4f[2][3] = 1;
9236         decal->vertex3f[0][0] = v0[0];
9237         decal->vertex3f[0][1] = v0[1];
9238         decal->vertex3f[0][2] = v0[2];
9239         decal->vertex3f[1][0] = v1[0];
9240         decal->vertex3f[1][1] = v1[1];
9241         decal->vertex3f[1][2] = v1[2];
9242         decal->vertex3f[2][0] = v2[0];
9243         decal->vertex3f[2][1] = v2[1];
9244         decal->vertex3f[2][2] = v2[2];
9245         decal->texcoord2f[0][0] = t0[0];
9246         decal->texcoord2f[0][1] = t0[1];
9247         decal->texcoord2f[1][0] = t1[0];
9248         decal->texcoord2f[1][1] = t1[1];
9249         decal->texcoord2f[2][0] = t2[0];
9250         decal->texcoord2f[2][1] = t2[1];
9251         TriangleNormal(v0, v1, v2, decal->plane);
9252         VectorNormalize(decal->plane);
9253         decal->plane[3] = DotProduct(v0, decal->plane);
9254 }
9255
9256 extern cvar_t cl_decals_bias;
9257 extern cvar_t cl_decals_models;
9258 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9259 // baseparms, parms, temps
9260 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)
9261 {
9262         int cornerindex;
9263         int index;
9264         float v[9][3];
9265         const float *vertex3f;
9266         const float *normal3f;
9267         int numpoints;
9268         float points[2][9][3];
9269         float temp[3];
9270         float tc[9][2];
9271         float f;
9272         float c[9][4];
9273         const int *e;
9274
9275         e = rsurface.modelelement3i + 3*triangleindex;
9276
9277         vertex3f = rsurface.modelvertex3f;
9278         normal3f = rsurface.modelnormal3f;
9279
9280         if (normal3f)
9281         {
9282                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9283                 {
9284                         index = 3*e[cornerindex];
9285                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9286                 }
9287         }
9288         else
9289         {
9290                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9291                 {
9292                         index = 3*e[cornerindex];
9293                         VectorCopy(vertex3f + index, v[cornerindex]);
9294                 }
9295         }
9296
9297         // cull backfaces
9298         //TriangleNormal(v[0], v[1], v[2], normal);
9299         //if (DotProduct(normal, localnormal) < 0.0f)
9300         //      continue;
9301         // clip by each of the box planes formed from the projection matrix
9302         // if anything survives, we emit the decal
9303         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]);
9304         if (numpoints < 3)
9305                 return;
9306         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]);
9307         if (numpoints < 3)
9308                 return;
9309         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]);
9310         if (numpoints < 3)
9311                 return;
9312         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]);
9313         if (numpoints < 3)
9314                 return;
9315         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]);
9316         if (numpoints < 3)
9317                 return;
9318         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]);
9319         if (numpoints < 3)
9320                 return;
9321         // some part of the triangle survived, so we have to accept it...
9322         if (dynamic)
9323         {
9324                 // dynamic always uses the original triangle
9325                 numpoints = 3;
9326                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9327                 {
9328                         index = 3*e[cornerindex];
9329                         VectorCopy(vertex3f + index, v[cornerindex]);
9330                 }
9331         }
9332         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9333         {
9334                 // convert vertex positions to texcoords
9335                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9336                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9337                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9338                 // calculate distance fade from the projection origin
9339                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9340                 f = bound(0.0f, f, 1.0f);
9341                 c[cornerindex][0] = r * f;
9342                 c[cornerindex][1] = g * f;
9343                 c[cornerindex][2] = b * f;
9344                 c[cornerindex][3] = 1.0f;
9345                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9346         }
9347         if (dynamic)
9348                 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);
9349         else
9350                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9351                         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);
9352 }
9353 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)
9354 {
9355         matrix4x4_t projection;
9356         decalsystem_t *decalsystem;
9357         qboolean dynamic;
9358         dp_model_t *model;
9359         const msurface_t *surface;
9360         const msurface_t *surfaces;
9361         const int *surfacelist;
9362         const texture_t *texture;
9363         int numtriangles;
9364         int numsurfacelist;
9365         int surfacelistindex;
9366         int surfaceindex;
9367         int triangleindex;
9368         float localorigin[3];
9369         float localnormal[3];
9370         float localmins[3];
9371         float localmaxs[3];
9372         float localsize;
9373         //float normal[3];
9374         float planes[6][4];
9375         float angles[3];
9376         bih_t *bih;
9377         int bih_triangles_count;
9378         int bih_triangles[256];
9379         int bih_surfaces[256];
9380
9381         decalsystem = &ent->decalsystem;
9382         model = ent->model;
9383         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9384         {
9385                 R_DecalSystem_Reset(&ent->decalsystem);
9386                 return;
9387         }
9388
9389         if (!model->brush.data_leafs && !cl_decals_models.integer)
9390         {
9391                 if (decalsystem->model)
9392                         R_DecalSystem_Reset(decalsystem);
9393                 return;
9394         }
9395
9396         if (decalsystem->model != model)
9397                 R_DecalSystem_Reset(decalsystem);
9398         decalsystem->model = model;
9399
9400         RSurf_ActiveModelEntity(ent, true, false, false);
9401
9402         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9403         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9404         VectorNormalize(localnormal);
9405         localsize = worldsize*rsurface.inversematrixscale;
9406         localmins[0] = localorigin[0] - localsize;
9407         localmins[1] = localorigin[1] - localsize;
9408         localmins[2] = localorigin[2] - localsize;
9409         localmaxs[0] = localorigin[0] + localsize;
9410         localmaxs[1] = localorigin[1] + localsize;
9411         localmaxs[2] = localorigin[2] + localsize;
9412
9413         //VectorCopy(localnormal, planes[4]);
9414         //VectorVectors(planes[4], planes[2], planes[0]);
9415         AnglesFromVectors(angles, localnormal, NULL, false);
9416         AngleVectors(angles, planes[0], planes[2], planes[4]);
9417         VectorNegate(planes[0], planes[1]);
9418         VectorNegate(planes[2], planes[3]);
9419         VectorNegate(planes[4], planes[5]);
9420         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9421         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9422         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9423         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9424         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9425         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9426
9427 #if 1
9428 // works
9429 {
9430         matrix4x4_t forwardprojection;
9431         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9432         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9433 }
9434 #else
9435 // broken
9436 {
9437         float projectionvector[4][3];
9438         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9439         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9440         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9441         projectionvector[0][0] = planes[0][0] * ilocalsize;
9442         projectionvector[0][1] = planes[1][0] * ilocalsize;
9443         projectionvector[0][2] = planes[2][0] * ilocalsize;
9444         projectionvector[1][0] = planes[0][1] * ilocalsize;
9445         projectionvector[1][1] = planes[1][1] * ilocalsize;
9446         projectionvector[1][2] = planes[2][1] * ilocalsize;
9447         projectionvector[2][0] = planes[0][2] * ilocalsize;
9448         projectionvector[2][1] = planes[1][2] * ilocalsize;
9449         projectionvector[2][2] = planes[2][2] * ilocalsize;
9450         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9451         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9452         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9453         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9454 }
9455 #endif
9456
9457         dynamic = model->surfmesh.isanimated;
9458         numsurfacelist = model->nummodelsurfaces;
9459         surfacelist = model->sortedmodelsurfaces;
9460         surfaces = model->data_surfaces;
9461
9462         bih = NULL;
9463         bih_triangles_count = -1;
9464         if(!dynamic)
9465         {
9466                 if(model->render_bih.numleafs)
9467                         bih = &model->render_bih;
9468                 else if(model->collision_bih.numleafs)
9469                         bih = &model->collision_bih;
9470         }
9471         if(bih)
9472                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9473         if(bih_triangles_count == 0)
9474                 return;
9475         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9476                 return;
9477         if(bih_triangles_count > 0)
9478         {
9479                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9480                 {
9481                         surfaceindex = bih_surfaces[triangleindex];
9482                         surface = surfaces + surfaceindex;
9483                         texture = surface->texture;
9484                         if (!texture)
9485                                 continue;
9486                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9487                                 continue;
9488                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9489                                 continue;
9490                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9491                 }
9492         }
9493         else
9494         {
9495                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9496                 {
9497                         surfaceindex = surfacelist[surfacelistindex];
9498                         surface = surfaces + surfaceindex;
9499                         // check cull box first because it rejects more than any other check
9500                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9501                                 continue;
9502                         // skip transparent surfaces
9503                         texture = surface->texture;
9504                         if (!texture)
9505                                 continue;
9506                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9507                                 continue;
9508                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9509                                 continue;
9510                         numtriangles = surface->num_triangles;
9511                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9512                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9513                 }
9514         }
9515 }
9516
9517 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9518 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)
9519 {
9520         int renderentityindex;
9521         float worldmins[3];
9522         float worldmaxs[3];
9523         entity_render_t *ent;
9524
9525         worldmins[0] = worldorigin[0] - worldsize;
9526         worldmins[1] = worldorigin[1] - worldsize;
9527         worldmins[2] = worldorigin[2] - worldsize;
9528         worldmaxs[0] = worldorigin[0] + worldsize;
9529         worldmaxs[1] = worldorigin[1] + worldsize;
9530         worldmaxs[2] = worldorigin[2] + worldsize;
9531
9532         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9533
9534         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9535         {
9536                 ent = r_refdef.scene.entities[renderentityindex];
9537                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9538                         continue;
9539
9540                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9541         }
9542 }
9543
9544 typedef struct r_decalsystem_splatqueue_s
9545 {
9546         vec3_t worldorigin;
9547         vec3_t worldnormal;
9548         float color[4];
9549         float tcrange[4];
9550         float worldsize;
9551         unsigned int decalsequence;
9552 }
9553 r_decalsystem_splatqueue_t;
9554
9555 int r_decalsystem_numqueued = 0;
9556 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9557
9558 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)
9559 {
9560         r_decalsystem_splatqueue_t *queue;
9561
9562         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9563                 return;
9564
9565         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9566         VectorCopy(worldorigin, queue->worldorigin);
9567         VectorCopy(worldnormal, queue->worldnormal);
9568         Vector4Set(queue->color, r, g, b, a);
9569         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9570         queue->worldsize = worldsize;
9571         queue->decalsequence = cl.decalsequence++;
9572 }
9573
9574 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9575 {
9576         int i;
9577         r_decalsystem_splatqueue_t *queue;
9578
9579         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9580                 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);
9581         r_decalsystem_numqueued = 0;
9582 }
9583
9584 extern cvar_t cl_decals_max;
9585 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9586 {
9587         int i;
9588         decalsystem_t *decalsystem = &ent->decalsystem;
9589         int numdecals;
9590         unsigned int killsequence;
9591         tridecal_t *decal;
9592         float frametime;
9593         float lifetime;
9594
9595         if (!decalsystem->numdecals)
9596                 return;
9597
9598         if (r_showsurfaces.integer)
9599                 return;
9600
9601         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9602         {
9603                 R_DecalSystem_Reset(decalsystem);
9604                 return;
9605         }
9606
9607         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9608         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9609
9610         if (decalsystem->lastupdatetime)
9611                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9612         else
9613                 frametime = 0;
9614         decalsystem->lastupdatetime = r_refdef.scene.time;
9615         numdecals = decalsystem->numdecals;
9616
9617         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9618         {
9619                 if (decal->color4f[0][3])
9620                 {
9621                         decal->lived += frametime;
9622                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9623                         {
9624                                 memset(decal, 0, sizeof(*decal));
9625                                 if (decalsystem->freedecal > i)
9626                                         decalsystem->freedecal = i;
9627                         }
9628                 }
9629         }
9630         decal = decalsystem->decals;
9631         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9632                 numdecals--;
9633
9634         // collapse the array by shuffling the tail decals into the gaps
9635         for (;;)
9636         {
9637                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9638                         decalsystem->freedecal++;
9639                 if (decalsystem->freedecal == numdecals)
9640                         break;
9641                 decal[decalsystem->freedecal] = decal[--numdecals];
9642         }
9643
9644         decalsystem->numdecals = numdecals;
9645
9646         if (numdecals <= 0)
9647         {
9648                 // if there are no decals left, reset decalsystem
9649                 R_DecalSystem_Reset(decalsystem);
9650         }
9651 }
9652
9653 extern skinframe_t *decalskinframe;
9654 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9655 {
9656         int i;
9657         decalsystem_t *decalsystem = &ent->decalsystem;
9658         int numdecals;
9659         tridecal_t *decal;
9660         float faderate;
9661         float alpha;
9662         float *v3f;
9663         float *c4f;
9664         float *t2f;
9665         const int *e;
9666         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9667         int numtris = 0;
9668
9669         numdecals = decalsystem->numdecals;
9670         if (!numdecals)
9671                 return;
9672
9673         if (r_showsurfaces.integer)
9674                 return;
9675
9676         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9677         {
9678                 R_DecalSystem_Reset(decalsystem);
9679                 return;
9680         }
9681
9682         // if the model is static it doesn't matter what value we give for
9683         // wantnormals and wanttangents, so this logic uses only rules applicable
9684         // to a model, knowing that they are meaningless otherwise
9685         RSurf_ActiveModelEntity(ent, false, false, false);
9686
9687         decalsystem->lastupdatetime = r_refdef.scene.time;
9688
9689         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9690
9691         // update vertex positions for animated models
9692         v3f = decalsystem->vertex3f;
9693         c4f = decalsystem->color4f;
9694         t2f = decalsystem->texcoord2f;
9695         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9696         {
9697                 if (!decal->color4f[0][3])
9698                         continue;
9699
9700                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9701                         continue;
9702
9703                 // skip backfaces
9704                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9705                         continue;
9706
9707                 // update color values for fading decals
9708                 if (decal->lived >= cl_decals_time.value)
9709                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9710                 else
9711                         alpha = 1.0f;
9712
9713                 c4f[ 0] = decal->color4f[0][0] * alpha;
9714                 c4f[ 1] = decal->color4f[0][1] * alpha;
9715                 c4f[ 2] = decal->color4f[0][2] * alpha;
9716                 c4f[ 3] = 1;
9717                 c4f[ 4] = decal->color4f[1][0] * alpha;
9718                 c4f[ 5] = decal->color4f[1][1] * alpha;
9719                 c4f[ 6] = decal->color4f[1][2] * alpha;
9720                 c4f[ 7] = 1;
9721                 c4f[ 8] = decal->color4f[2][0] * alpha;
9722                 c4f[ 9] = decal->color4f[2][1] * alpha;
9723                 c4f[10] = decal->color4f[2][2] * alpha;
9724                 c4f[11] = 1;
9725
9726                 t2f[0] = decal->texcoord2f[0][0];
9727                 t2f[1] = decal->texcoord2f[0][1];
9728                 t2f[2] = decal->texcoord2f[1][0];
9729                 t2f[3] = decal->texcoord2f[1][1];
9730                 t2f[4] = decal->texcoord2f[2][0];
9731                 t2f[5] = decal->texcoord2f[2][1];
9732
9733                 // update vertex positions for animated models
9734                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9735                 {
9736                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9737                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9738                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9739                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9740                 }
9741                 else
9742                 {
9743                         VectorCopy(decal->vertex3f[0], v3f);
9744                         VectorCopy(decal->vertex3f[1], v3f + 3);
9745                         VectorCopy(decal->vertex3f[2], v3f + 6);
9746                 }
9747
9748                 if (r_refdef.fogenabled)
9749                 {
9750                         alpha = RSurf_FogVertex(v3f);
9751                         VectorScale(c4f, alpha, c4f);
9752                         alpha = RSurf_FogVertex(v3f + 3);
9753                         VectorScale(c4f + 4, alpha, c4f + 4);
9754                         alpha = RSurf_FogVertex(v3f + 6);
9755                         VectorScale(c4f + 8, alpha, c4f + 8);
9756                 }
9757
9758                 v3f += 9;
9759                 c4f += 12;
9760                 t2f += 6;
9761                 numtris++;
9762         }
9763
9764         if (numtris > 0)
9765         {
9766                 r_refdef.stats[r_stat_drawndecals] += numtris;
9767
9768                 // now render the decals all at once
9769                 // (this assumes they all use one particle font texture!)
9770                 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);
9771 //              R_Mesh_ResetTextureState();
9772                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9773                 GL_DepthMask(false);
9774                 GL_DepthRange(0, 1);
9775                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9776                 GL_DepthTest(true);
9777                 GL_CullFace(GL_NONE);
9778                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9779                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9780                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9781         }
9782 }
9783
9784 static void R_DrawModelDecals(void)
9785 {
9786         int i, numdecals;
9787
9788         // fade faster when there are too many decals
9789         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9790         for (i = 0;i < r_refdef.scene.numentities;i++)
9791                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9792
9793         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9794         for (i = 0;i < r_refdef.scene.numentities;i++)
9795                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9796                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9797
9798         R_DecalSystem_ApplySplatEntitiesQueue();
9799
9800         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9801         for (i = 0;i < r_refdef.scene.numentities;i++)
9802                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9803
9804         r_refdef.stats[r_stat_totaldecals] += numdecals;
9805
9806         if (r_showsurfaces.integer || !r_drawdecals.integer)
9807                 return;
9808
9809         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9810
9811         for (i = 0;i < r_refdef.scene.numentities;i++)
9812         {
9813                 if (!r_refdef.viewcache.entityvisible[i])
9814                         continue;
9815                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9816                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9817         }
9818 }
9819
9820 static void R_DrawDebugModel(void)
9821 {
9822         entity_render_t *ent = rsurface.entity;
9823         int i, j, flagsmask;
9824         const msurface_t *surface;
9825         dp_model_t *model = ent->model;
9826
9827         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9828                 return;
9829
9830         if (r_showoverdraw.value > 0)
9831         {
9832                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9833                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9834                 R_SetupShader_Generic_NoTexture(false, false);
9835                 GL_DepthTest(false);
9836                 GL_DepthMask(false);
9837                 GL_DepthRange(0, 1);
9838                 GL_BlendFunc(GL_ONE, GL_ONE);
9839                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9840                 {
9841                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9842                                 continue;
9843                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9844                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9845                         {
9846                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9847                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9848                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9849                                         GL_Color(c, 0, 0, 1.0f);
9850                                 else if (ent == r_refdef.scene.worldentity)
9851                                         GL_Color(c, c, c, 1.0f);
9852                                 else
9853                                         GL_Color(0, c, 0, 1.0f);
9854                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9855                                 RSurf_DrawBatch();
9856                         }
9857                 }
9858                 rsurface.texture = NULL;
9859         }
9860
9861         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9862
9863 //      R_Mesh_ResetTextureState();
9864         R_SetupShader_Generic_NoTexture(false, false);
9865         GL_DepthRange(0, 1);
9866         GL_DepthTest(!r_showdisabledepthtest.integer);
9867         GL_DepthMask(false);
9868         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9869
9870         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9871         {
9872                 int triangleindex;
9873                 int bihleafindex;
9874                 qboolean cullbox = false;
9875                 const q3mbrush_t *brush;
9876                 const bih_t *bih = &model->collision_bih;
9877                 const bih_leaf_t *bihleaf;
9878                 float vertex3f[3][3];
9879                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9880                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9881                 {
9882                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9883                                 continue;
9884                         switch (bihleaf->type)
9885                         {
9886                         case BIH_BRUSH:
9887                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9888                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9889                                 {
9890                                         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);
9891                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9892                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9893                                 }
9894                                 break;
9895                         case BIH_COLLISIONTRIANGLE:
9896                                 triangleindex = bihleaf->itemindex;
9897                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9898                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9899                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9900                                 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);
9901                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9902                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9903                                 break;
9904                         case BIH_RENDERTRIANGLE:
9905                                 triangleindex = bihleaf->itemindex;
9906                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9907                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9908                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9909                                 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);
9910                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9911                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9912                                 break;
9913                         }
9914                 }
9915         }
9916
9917         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9918
9919 #ifndef USE_GLES2
9920         if (r_showtris.value > 0 && qglPolygonMode)
9921         {
9922                 if (r_showdisabledepthtest.integer)
9923                 {
9924                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9925                         GL_DepthMask(false);
9926                 }
9927                 else
9928                 {
9929                         GL_BlendFunc(GL_ONE, GL_ZERO);
9930                         GL_DepthMask(true);
9931                 }
9932                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9933                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9934                 {
9935                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9936                                 continue;
9937                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9938                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9939                         {
9940                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9941                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9942                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9943                                 else if (ent == r_refdef.scene.worldentity)
9944                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9945                                 else
9946                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9947                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9948                                 RSurf_DrawBatch();
9949                         }
9950                 }
9951                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9952                 rsurface.texture = NULL;
9953         }
9954
9955 # if 0
9956         // FIXME!  implement r_shownormals with just triangles
9957         if (r_shownormals.value != 0 && qglBegin)
9958         {
9959                 int l, k;
9960                 vec3_t v;
9961                 if (r_showdisabledepthtest.integer)
9962                 {
9963                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9964                         GL_DepthMask(false);
9965                 }
9966                 else
9967                 {
9968                         GL_BlendFunc(GL_ONE, GL_ZERO);
9969                         GL_DepthMask(true);
9970                 }
9971                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9972                 {
9973                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9974                                 continue;
9975                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9976                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9977                         {
9978                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9979                                 qglBegin(GL_LINES);
9980                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9981                                 {
9982                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9983                                         {
9984                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9985                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9986                                                 qglVertex3f(v[0], v[1], v[2]);
9987                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9988                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9989                                                 qglVertex3f(v[0], v[1], v[2]);
9990                                         }
9991                                 }
9992                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9993                                 {
9994                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9995                                         {
9996                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9997                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9998                                                 qglVertex3f(v[0], v[1], v[2]);
9999                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10000                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10001                                                 qglVertex3f(v[0], v[1], v[2]);
10002                                         }
10003                                 }
10004                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10005                                 {
10006                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10007                                         {
10008                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10009                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10010                                                 qglVertex3f(v[0], v[1], v[2]);
10011                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10012                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10013                                                 qglVertex3f(v[0], v[1], v[2]);
10014                                         }
10015                                 }
10016                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10017                                 {
10018                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10019                                         {
10020                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10021                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10022                                                 qglVertex3f(v[0], v[1], v[2]);
10023                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10024                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10025                                                 qglVertex3f(v[0], v[1], v[2]);
10026                                         }
10027                                 }
10028                                 qglEnd();
10029                                 CHECKGLERROR
10030                         }
10031                 }
10032                 rsurface.texture = NULL;
10033         }
10034 # endif
10035 #endif
10036 }
10037
10038 int r_maxsurfacelist = 0;
10039 const msurface_t **r_surfacelist = NULL;
10040 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10041 {
10042         int i, j, endj, flagsmask;
10043         dp_model_t *model = ent->model;
10044         msurface_t *surfaces;
10045         unsigned char *update;
10046         int numsurfacelist = 0;
10047         if (model == NULL)
10048                 return;
10049
10050         if (r_maxsurfacelist < model->num_surfaces)
10051         {
10052                 r_maxsurfacelist = model->num_surfaces;
10053                 if (r_surfacelist)
10054                         Mem_Free((msurface_t **)r_surfacelist);
10055                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10056         }
10057
10058         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10059                 RSurf_ActiveModelEntity(ent, false, false, false);
10060         else if (prepass)
10061                 RSurf_ActiveModelEntity(ent, true, true, true);
10062         else if (depthonly)
10063                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10064         else
10065                 RSurf_ActiveModelEntity(ent, true, true, false);
10066
10067         surfaces = model->data_surfaces;
10068         update = model->brushq1.lightmapupdateflags;
10069
10070         // update light styles
10071         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10072         {
10073                 model_brush_lightstyleinfo_t *style;
10074                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10075                 {
10076                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10077                         {
10078                                 int *list = style->surfacelist;
10079                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10080                                 for (j = 0;j < style->numsurfaces;j++)
10081                                         update[list[j]] = true;
10082                         }
10083                 }
10084         }
10085
10086         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10087
10088         if (debug)
10089         {
10090                 R_DrawDebugModel();
10091                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10092                 return;
10093         }
10094
10095         rsurface.lightmaptexture = NULL;
10096         rsurface.deluxemaptexture = NULL;
10097         rsurface.uselightmaptexture = false;
10098         rsurface.texture = NULL;
10099         rsurface.rtlight = NULL;
10100         numsurfacelist = 0;
10101         // add visible surfaces to draw list
10102         if (ent == r_refdef.scene.worldentity)
10103         {
10104                 // for the world entity, check surfacevisible
10105                 for (i = 0;i < model->nummodelsurfaces;i++)
10106                 {
10107                         j = model->sortedmodelsurfaces[i];
10108                         if (r_refdef.viewcache.world_surfacevisible[j])
10109                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10110                 }
10111         }
10112         else if (ui)
10113         {
10114                 // for ui we have to preserve the order of surfaces
10115                 for (i = 0; i < model->nummodelsurfaces; i++)
10116                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10117         }
10118         else
10119         {
10120                 // add all surfaces
10121                 for (i = 0; i < model->nummodelsurfaces; i++)
10122                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10123         }
10124         // don't do anything if there were no surfaces
10125         if (!numsurfacelist)
10126         {
10127                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10128                 return;
10129         }
10130         // update lightmaps if needed
10131         if (update)
10132         {
10133                 int updated = 0;
10134                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10135                 {
10136                         if (update[j])
10137                         {
10138                                 updated++;
10139                                 R_BuildLightMap(ent, surfaces + j);
10140                         }
10141                 }
10142         }
10143
10144         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10145
10146         // add to stats if desired
10147         if (r_speeds.integer && !skysurfaces && !depthonly)
10148         {
10149                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10150                 for (j = 0;j < numsurfacelist;j++)
10151                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10152         }
10153
10154         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10155 }
10156
10157 void R_DebugLine(vec3_t start, vec3_t end)
10158 {
10159         dp_model_t *mod = CL_Mesh_UI();
10160         msurface_t *surf;
10161         int e0, e1, e2, e3;
10162         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10163         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10164         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10165         vec4_t w[2], s[2];
10166
10167         // transform to screen coords first
10168         Vector4Set(w[0], start[0], start[1], start[2], 1);
10169         Vector4Set(w[1], end[0], end[1], end[2], 1);
10170         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10171         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10172         x1 = s[0][0] * vid_conwidth.value / vid.width;
10173         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10174         x2 = s[1][0] * vid_conwidth.value / vid.width;
10175         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10176         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10177
10178         // add the line to the UI mesh for drawing later
10179
10180         // width is measured in real pixels
10181         if (fabs(x2 - x1) > fabs(y2 - y1))
10182         {
10183                 offsetx = 0;
10184                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10185         }
10186         else
10187         {
10188                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10189                 offsety = 0;
10190         }
10191         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);
10192         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10193         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10194         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10195         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10196         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10197         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10198
10199 }
10200
10201
10202 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)
10203 {
10204         static texture_t texture;
10205
10206         // fake enough texture and surface state to render this geometry
10207
10208         texture.update_lastrenderframe = -1; // regenerate this texture
10209         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10210         texture.basealpha = 1.0f;
10211         texture.currentskinframe = skinframe;
10212         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10213         texture.offsetmapping = OFFSETMAPPING_OFF;
10214         texture.offsetscale = 1;
10215         texture.specularscalemod = 1;
10216         texture.specularpowermod = 1;
10217         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10218
10219         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10220 }
10221
10222 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)
10223 {
10224         static msurface_t surface;
10225         const msurface_t *surfacelist = &surface;
10226
10227         // fake enough texture and surface state to render this geometry
10228         surface.texture = texture;
10229         surface.num_triangles = numtriangles;
10230         surface.num_firsttriangle = firsttriangle;
10231         surface.num_vertices = numvertices;
10232         surface.num_firstvertex = firstvertex;
10233
10234         // now render it
10235         rsurface.texture = R_GetCurrentTexture(surface.texture);
10236         rsurface.lightmaptexture = NULL;
10237         rsurface.deluxemaptexture = NULL;
10238         rsurface.uselightmaptexture = false;
10239         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10240 }