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