]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
cc0895cd3bbbcb34d1f0c8a1aeca07f882426a2e
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qbool r_loadnormalmap;
48 static qbool r_loadgloss;
49 qbool r_loadfog;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 3 shows an approximation to vertex or object color (for a very approximate view of the game)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CF_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
160 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode; the default setting of 0 uses a framebuffer render when required, and renders directly to the screen otherwise"};
161 cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
162 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
163 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
164 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
165 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
166 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
167 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
168 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
169
170 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
171 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
172 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
173 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
174 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
175 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
176 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
177 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
178 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
179 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
180 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
181 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
182 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
183 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
184 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
185 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
189 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
190 cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"};
191
192 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
193 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
194 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
195 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
196 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
197 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
198 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
199 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
200 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
201
202 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
203 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
204 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
205 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
206 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
207
208 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
209 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
210
211 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
212 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
213 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
214 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
215 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
216 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
217
218 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
219 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
220 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
221 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
222 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
223 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
224 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
225 cvar_t r_hdr_irisadaptation_fade_up = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
226 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
227 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
228
229 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
230
231 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
232
233 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
234
235 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
236
237 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
238 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
239 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
240 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
241
242 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
243 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
244
245 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
246
247 // FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting.
248 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
249 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
250 {
251         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
252         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
253         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
254         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
255 };
256
257 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
258 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
259 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
260
261 extern cvar_t v_glslgamma_2d;
262
263 extern qbool v_flipped_state;
264
265 r_framebufferstate_t r_fb;
266
267 /// shadow volume bsp struct with automatically growing nodes buffer
268 svbsp_t r_svbsp;
269
270 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
271
272 rtexture_t *r_texture_blanknormalmap;
273 rtexture_t *r_texture_white;
274 rtexture_t *r_texture_grey128;
275 rtexture_t *r_texture_black;
276 rtexture_t *r_texture_notexture;
277 rtexture_t *r_texture_whitecube;
278 rtexture_t *r_texture_normalizationcube;
279 rtexture_t *r_texture_fogattenuation;
280 rtexture_t *r_texture_fogheighttexture;
281 rtexture_t *r_texture_gammaramps;
282 unsigned int r_texture_gammaramps_serial;
283 //rtexture_t *r_texture_fogintensity;
284 rtexture_t *r_texture_reflectcube;
285
286 // TODO: hash lookups?
287 typedef struct cubemapinfo_s
288 {
289         char basename[64];
290         rtexture_t *texture;
291 }
292 cubemapinfo_t;
293
294 int r_texture_numcubemaps;
295 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
296
297 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
298 unsigned int r_numqueries;
299 unsigned int r_maxqueries;
300
301 typedef struct r_qwskincache_s
302 {
303         char name[MAX_QPATH];
304         skinframe_t *skinframe;
305 }
306 r_qwskincache_t;
307
308 static r_qwskincache_t *r_qwskincache;
309 static int r_qwskincache_size;
310
311 /// vertex coordinates for a quad that covers the screen exactly
312 extern const float r_screenvertex3f[12];
313 const float r_screenvertex3f[12] =
314 {
315         0, 0, 0,
316         1, 0, 0,
317         1, 1, 0,
318         0, 1, 0
319 };
320
321 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
322 {
323         int i;
324         for (i = 0;i < verts;i++)
325         {
326                 out[0] = in[0] * r;
327                 out[1] = in[1] * g;
328                 out[2] = in[2] * b;
329                 out[3] = in[3];
330                 in += 4;
331                 out += 4;
332         }
333 }
334
335 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
336 {
337         int i;
338         for (i = 0;i < verts;i++)
339         {
340                 out[0] = r;
341                 out[1] = g;
342                 out[2] = b;
343                 out[3] = a;
344                 out += 4;
345         }
346 }
347
348 // FIXME: move this to client?
349 void FOG_clear(void)
350 {
351         if (gamemode == GAME_NEHAHRA)
352         {
353                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
354                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
355                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
356                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
357                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
358         }
359         r_refdef.fog_density = 0;
360         r_refdef.fog_red = 0;
361         r_refdef.fog_green = 0;
362         r_refdef.fog_blue = 0;
363         r_refdef.fog_alpha = 1;
364         r_refdef.fog_start = 0;
365         r_refdef.fog_end = 16384;
366         r_refdef.fog_height = 1<<30;
367         r_refdef.fog_fadedepth = 128;
368         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
369 }
370
371 static void R_BuildBlankTextures(void)
372 {
373         unsigned char data[4];
374         data[2] = 128; // normal X
375         data[1] = 128; // normal Y
376         data[0] = 255; // normal Z
377         data[3] = 255; // height
378         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
379         data[0] = 255;
380         data[1] = 255;
381         data[2] = 255;
382         data[3] = 255;
383         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
384         data[0] = 128;
385         data[1] = 128;
386         data[2] = 128;
387         data[3] = 255;
388         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
389         data[0] = 0;
390         data[1] = 0;
391         data[2] = 0;
392         data[3] = 255;
393         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
394 }
395
396 static void R_BuildNoTexture(void)
397 {
398         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
399 }
400
401 static void R_BuildWhiteCube(void)
402 {
403         unsigned char data[6*1*1*4];
404         memset(data, 255, sizeof(data));
405         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
406 }
407
408 static void R_BuildNormalizationCube(void)
409 {
410         int x, y, side;
411         vec3_t v;
412         vec_t s, t, intensity;
413 #define NORMSIZE 64
414         unsigned char *data;
415         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
416         for (side = 0;side < 6;side++)
417         {
418                 for (y = 0;y < NORMSIZE;y++)
419                 {
420                         for (x = 0;x < NORMSIZE;x++)
421                         {
422                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
423                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
424                                 switch(side)
425                                 {
426                                 default:
427                                 case 0:
428                                         v[0] = 1;
429                                         v[1] = -t;
430                                         v[2] = -s;
431                                         break;
432                                 case 1:
433                                         v[0] = -1;
434                                         v[1] = -t;
435                                         v[2] = s;
436                                         break;
437                                 case 2:
438                                         v[0] = s;
439                                         v[1] = 1;
440                                         v[2] = t;
441                                         break;
442                                 case 3:
443                                         v[0] = s;
444                                         v[1] = -1;
445                                         v[2] = -t;
446                                         break;
447                                 case 4:
448                                         v[0] = s;
449                                         v[1] = -t;
450                                         v[2] = 1;
451                                         break;
452                                 case 5:
453                                         v[0] = -s;
454                                         v[1] = -t;
455                                         v[2] = -1;
456                                         break;
457                                 }
458                                 intensity = 127.0f / sqrt(DotProduct(v, v));
459                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
460                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
461                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
462                                 data[((side*64+y)*64+x)*4+3] = 255;
463                         }
464                 }
465         }
466         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
467         Mem_Free(data);
468 }
469
470 static void R_BuildFogTexture(void)
471 {
472         int x, b;
473 #define FOGWIDTH 256
474         unsigned char data1[FOGWIDTH][4];
475         //unsigned char data2[FOGWIDTH][4];
476         double d, r, alpha;
477
478         r_refdef.fogmasktable_start = r_refdef.fog_start;
479         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
480         r_refdef.fogmasktable_range = r_refdef.fogrange;
481         r_refdef.fogmasktable_density = r_refdef.fog_density;
482
483         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
484         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
485         {
486                 d = (x * r - r_refdef.fogmasktable_start);
487                 if(developer_extra.integer)
488                         Con_DPrintf("%f ", d);
489                 d = max(0, d);
490                 if (r_fog_exp2.integer)
491                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
492                 else
493                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
494                 if(developer_extra.integer)
495                         Con_DPrintf(" : %f ", alpha);
496                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
497                 if(developer_extra.integer)
498                         Con_DPrintf(" = %f\n", alpha);
499                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
500         }
501
502         for (x = 0;x < FOGWIDTH;x++)
503         {
504                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
505                 data1[x][0] = b;
506                 data1[x][1] = b;
507                 data1[x][2] = b;
508                 data1[x][3] = 255;
509                 //data2[x][0] = 255 - b;
510                 //data2[x][1] = 255 - b;
511                 //data2[x][2] = 255 - b;
512                 //data2[x][3] = 255;
513         }
514         if (r_texture_fogattenuation)
515         {
516                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
517                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
518         }
519         else
520         {
521                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
522                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
523         }
524 }
525
526 static void R_BuildFogHeightTexture(void)
527 {
528         unsigned char *inpixels;
529         int size;
530         int x;
531         int y;
532         int j;
533         float c[4];
534         float f;
535         inpixels = NULL;
536         dp_strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
537         if (r_refdef.fogheighttexturename[0])
538                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
539         if (!inpixels)
540         {
541                 r_refdef.fog_height_tablesize = 0;
542                 if (r_texture_fogheighttexture)
543                         R_FreeTexture(r_texture_fogheighttexture);
544                 r_texture_fogheighttexture = NULL;
545                 if (r_refdef.fog_height_table2d)
546                         Mem_Free(r_refdef.fog_height_table2d);
547                 r_refdef.fog_height_table2d = NULL;
548                 if (r_refdef.fog_height_table1d)
549                         Mem_Free(r_refdef.fog_height_table1d);
550                 r_refdef.fog_height_table1d = NULL;
551                 return;
552         }
553         size = image_width;
554         r_refdef.fog_height_tablesize = size;
555         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
556         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
557         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
558         Mem_Free(inpixels);
559         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
560         // average fog color table accounting for every fog layer between a point
561         // and the camera.  (Note: attenuation is handled separately!)
562         for (y = 0;y < size;y++)
563         {
564                 for (x = 0;x < size;x++)
565                 {
566                         Vector4Clear(c);
567                         f = 0;
568                         if (x < y)
569                         {
570                                 for (j = x;j <= y;j++)
571                                 {
572                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
573                                         f++;
574                                 }
575                         }
576                         else
577                         {
578                                 for (j = x;j >= y;j--)
579                                 {
580                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
581                                         f++;
582                                 }
583                         }
584                         f = 1.0f / f;
585                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
586                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
587                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
588                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
589                 }
590         }
591         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
592 }
593
594 //=======================================================================================================================================================
595
596 static const char *builtinshaderstrings[] =
597 {
598 #include "shader_glsl.h"
599 0
600 };
601
602 //=======================================================================================================================================================
603
604 typedef struct shaderpermutationinfo_s
605 {
606         const char *pretext;
607         const char *name;
608 }
609 shaderpermutationinfo_t;
610
611 typedef struct shadermodeinfo_s
612 {
613         const char *sourcebasename;
614         const char *extension;
615         const char **builtinshaderstrings;
616         const char *pretext;
617         const char *name;
618         char *filename;
619         char *builtinstring;
620         int builtincrc;
621 }
622 shadermodeinfo_t;
623
624 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
625 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
626 {
627         {"#define USEDIFFUSE\n", " diffuse"},
628         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
629         {"#define USEVIEWTINT\n", " viewtint"},
630         {"#define USECOLORMAPPING\n", " colormapping"},
631         {"#define USESATURATION\n", " saturation"},
632         {"#define USEFOGINSIDE\n", " foginside"},
633         {"#define USEFOGOUTSIDE\n", " fogoutside"},
634         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
635         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
636         {"#define USEGAMMARAMPS\n", " gammaramps"},
637         {"#define USECUBEFILTER\n", " cubefilter"},
638         {"#define USEGLOW\n", " glow"},
639         {"#define USEBLOOM\n", " bloom"},
640         {"#define USESPECULAR\n", " specular"},
641         {"#define USEPOSTPROCESSING\n", " postprocessing"},
642         {"#define USEREFLECTION\n", " reflection"},
643         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
644         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
645         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
646         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
647         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
648         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
649         {"#define USEALPHAKILL\n", " alphakill"},
650         {"#define USEREFLECTCUBE\n", " reflectcube"},
651         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
652         {"#define USEBOUNCEGRID\n", " bouncegrid"},
653         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
654         {"#define USETRIPPY\n", " trippy"},
655         {"#define USEDEPTHRGB\n", " depthrgb"},
656         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
657         {"#define USESKELETAL\n", " skeletal"},
658         {"#define USEOCCLUDE\n", " occlude"}
659 };
660
661 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
662 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
663 {
664         // SHADERLANGUAGE_GLSL
665         {
666                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
667                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
668                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
669                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
683         },
684 };
685
686 struct r_glsl_permutation_s;
687 typedef struct r_glsl_permutation_s
688 {
689         /// hash lookup data
690         struct r_glsl_permutation_s *hashnext;
691         unsigned int mode;
692         uint64_t permutation;
693
694         /// indicates if we have tried compiling this permutation already
695         qbool compiled;
696         /// 0 if compilation failed
697         int program;
698         // texture units assigned to each detected uniform
699         int tex_Texture_First;
700         int tex_Texture_Second;
701         int tex_Texture_GammaRamps;
702         int tex_Texture_Normal;
703         int tex_Texture_Color;
704         int tex_Texture_Gloss;
705         int tex_Texture_Glow;
706         int tex_Texture_SecondaryNormal;
707         int tex_Texture_SecondaryColor;
708         int tex_Texture_SecondaryGloss;
709         int tex_Texture_SecondaryGlow;
710         int tex_Texture_Pants;
711         int tex_Texture_Shirt;
712         int tex_Texture_FogHeightTexture;
713         int tex_Texture_FogMask;
714         int tex_Texture_LightGrid;
715         int tex_Texture_Lightmap;
716         int tex_Texture_Deluxemap;
717         int tex_Texture_Attenuation;
718         int tex_Texture_Cube;
719         int tex_Texture_Refraction;
720         int tex_Texture_Reflection;
721         int tex_Texture_ShadowMap2D;
722         int tex_Texture_CubeProjection;
723         int tex_Texture_ScreenNormalMap;
724         int tex_Texture_ScreenDiffuse;
725         int tex_Texture_ScreenSpecular;
726         int tex_Texture_ReflectMask;
727         int tex_Texture_ReflectCube;
728         int tex_Texture_BounceGrid;
729         /// locations of detected uniforms in program object, or -1 if not found
730         int loc_Texture_First;
731         int loc_Texture_Second;
732         int loc_Texture_GammaRamps;
733         int loc_Texture_Normal;
734         int loc_Texture_Color;
735         int loc_Texture_Gloss;
736         int loc_Texture_Glow;
737         int loc_Texture_SecondaryNormal;
738         int loc_Texture_SecondaryColor;
739         int loc_Texture_SecondaryGloss;
740         int loc_Texture_SecondaryGlow;
741         int loc_Texture_Pants;
742         int loc_Texture_Shirt;
743         int loc_Texture_FogHeightTexture;
744         int loc_Texture_FogMask;
745         int loc_Texture_LightGrid;
746         int loc_Texture_Lightmap;
747         int loc_Texture_Deluxemap;
748         int loc_Texture_Attenuation;
749         int loc_Texture_Cube;
750         int loc_Texture_Refraction;
751         int loc_Texture_Reflection;
752         int loc_Texture_ShadowMap2D;
753         int loc_Texture_CubeProjection;
754         int loc_Texture_ScreenNormalMap;
755         int loc_Texture_ScreenDiffuse;
756         int loc_Texture_ScreenSpecular;
757         int loc_Texture_ReflectMask;
758         int loc_Texture_ReflectCube;
759         int loc_Texture_BounceGrid;
760         int loc_Alpha;
761         int loc_BloomBlur_Parameters;
762         int loc_ClientTime;
763         int loc_Color_Ambient;
764         int loc_Color_Diffuse;
765         int loc_Color_Specular;
766         int loc_Color_Glow;
767         int loc_Color_Pants;
768         int loc_Color_Shirt;
769         int loc_DeferredColor_Ambient;
770         int loc_DeferredColor_Diffuse;
771         int loc_DeferredColor_Specular;
772         int loc_DeferredMod_Diffuse;
773         int loc_DeferredMod_Specular;
774         int loc_DistortScaleRefractReflect;
775         int loc_EyePosition;
776         int loc_FogColor;
777         int loc_FogHeightFade;
778         int loc_FogPlane;
779         int loc_FogPlaneViewDist;
780         int loc_FogRangeRecip;
781         int loc_LightColor;
782         int loc_LightDir;
783         int loc_LightGridMatrix;
784         int loc_LightGridNormalMatrix;
785         int loc_LightPosition;
786         int loc_OffsetMapping_ScaleSteps;
787         int loc_OffsetMapping_LodDistance;
788         int loc_OffsetMapping_Bias;
789         int loc_PixelSize;
790         int loc_ReflectColor;
791         int loc_ReflectFactor;
792         int loc_ReflectOffset;
793         int loc_RefractColor;
794         int loc_Saturation;
795         int loc_ScreenCenterRefractReflect;
796         int loc_ScreenScaleRefractReflect;
797         int loc_ScreenToDepth;
798         int loc_ShadowMap_Parameters;
799         int loc_ShadowMap_TextureScale;
800         int loc_SpecularPower;
801         int loc_Skeletal_Transform12;
802         int loc_UserVec1;
803         int loc_UserVec2;
804         int loc_UserVec3;
805         int loc_UserVec4;
806         int loc_ColorFringe;
807         int loc_ViewTintColor;
808         int loc_ViewToLight;
809         int loc_ModelToLight;
810         int loc_TexMatrix;
811         int loc_BackgroundTexMatrix;
812         int loc_ModelViewProjectionMatrix;
813         int loc_ModelViewMatrix;
814         int loc_PixelToScreenTexCoord;
815         int loc_ModelToReflectCube;
816         int loc_ShadowMapMatrix;
817         int loc_BloomColorSubtract;
818         int loc_NormalmapScrollBlend;
819         int loc_BounceGridMatrix;
820         int loc_BounceGridIntensity;
821         /// uniform block bindings
822         int ubibind_Skeletal_Transform12_UniformBlock;
823         /// uniform block indices
824         int ubiloc_Skeletal_Transform12_UniformBlock;
825 }
826 r_glsl_permutation_t;
827
828 #define SHADERPERMUTATION_HASHSIZE 256
829
830
831 // non-degradable "lightweight" shader parameters to keep the permutations simpler
832 // these can NOT degrade! only use for simple stuff
833 enum
834 {
835         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
836         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
837         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
838         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
839         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
840         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
841         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
842         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
843         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
844         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
845         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
846         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
847         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
848         SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
849         SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
850 };
851 #define SHADERSTATICPARMS_COUNT 15
852
853 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
854 static int shaderstaticparms_count = 0;
855
856 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
857 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
858
859 extern qbool r_shadow_shadowmapsampler;
860 extern int r_shadow_shadowmappcf;
861 qbool R_CompileShader_CheckStaticParms(void)
862 {
863         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
864         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
865         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
866
867         // detect all
868         if (r_glsl_saturation_redcompensate.integer)
869                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
870         if (r_glsl_vertextextureblend_usebothalphas.integer)
871                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
872         if (r_shadow_glossexact.integer)
873                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
874         if (r_glsl_postprocess.integer)
875         {
876                 if (r_glsl_postprocess_uservec1_enable.integer)
877                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
878                 if (r_glsl_postprocess_uservec2_enable.integer)
879                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
880                 if (r_glsl_postprocess_uservec3_enable.integer)
881                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
882                 if (r_glsl_postprocess_uservec4_enable.integer)
883                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
884         }
885         if (r_fxaa.integer)
886                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
887         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
888                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
889
890         if (r_shadow_shadowmapsampler)
891                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
892         if (r_shadow_shadowmappcf > 1)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
894         else if (r_shadow_shadowmappcf)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
896         if (r_celshading.integer)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
898         if (r_celoutlines.integer)
899                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
900         if (r_colorfringe.value)
901                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
902
903         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
904 }
905
906 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
907         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
908                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
909         else \
910                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
911 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
912 {
913         shaderstaticparms_count = 0;
914
915         // emit all
916         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
917         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
918         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
919         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
931 }
932
933 /// information about each possible shader permutation
934 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
935 /// currently selected permutation
936 r_glsl_permutation_t *r_glsl_permutation;
937 /// storage for permutations linked in the hash table
938 memexpandablearray_t r_glsl_permutationarray;
939
940 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
941 {
942         //unsigned int hashdepth = 0;
943         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
944         r_glsl_permutation_t *p;
945         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
946         {
947                 if (p->mode == mode && p->permutation == permutation)
948                 {
949                         //if (hashdepth > 10)
950                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
951                         return p;
952                 }
953                 //hashdepth++;
954         }
955         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
956         p->mode = mode;
957         p->permutation = permutation;
958         p->hashnext = r_glsl_permutationhash[mode][hashindex];
959         r_glsl_permutationhash[mode][hashindex] = p;
960         //if (hashdepth > 10)
961         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
962         return p;
963 }
964
965 static char *R_ShaderStrCat(const char **strings)
966 {
967         char *string, *s;
968         const char **p = strings;
969         const char *t;
970         size_t len = 0;
971         for (p = strings;(t = *p);p++)
972                 len += strlen(t);
973         len++;
974         s = string = (char *)Mem_Alloc(r_main_mempool, len);
975         len = 0;
976         for (p = strings;(t = *p);p++)
977         {
978                 len = strlen(t);
979                 memcpy(s, t, len);
980                 s += len;
981         }
982         *s = 0;
983         return string;
984 }
985
986 static char *R_ShaderStrCat(const char **strings);
987 static void R_InitShaderModeInfo(void)
988 {
989         int i, language;
990         shadermodeinfo_t *modeinfo;
991         // 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)
992         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
993         {
994                 for (i = 0; i < SHADERMODE_COUNT; i++)
995                 {
996                         char filename[MAX_QPATH];
997                         modeinfo = &shadermodeinfo[language][i];
998                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
999                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1000                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1001                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1002                 }
1003         }
1004 }
1005
1006 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1007 {
1008         char *shaderstring;
1009         // if the mode has no filename we have to return the builtin string
1010         if (builtinonly || !modeinfo->filename)
1011                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1012         // note that FS_LoadFile appends a 0 byte to make it a valid string
1013         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1014         if (shaderstring)
1015         {
1016                 if (printfromdisknotice)
1017                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1018                 return shaderstring;
1019         }
1020         // fall back to builtinstring
1021         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1022 }
1023
1024 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1025 {
1026         unsigned i;
1027         int ubibind;
1028         int sampler;
1029         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1030         char *sourcestring;
1031         char permutationname[256];
1032         int vertstrings_count = 0;
1033         int geomstrings_count = 0;
1034         int fragstrings_count = 0;
1035         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1036         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1037         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1038
1039         if (p->compiled)
1040                 return;
1041         p->compiled = true;
1042         p->program = 0;
1043
1044         permutationname[0] = 0;
1045         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1046
1047         dp_strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1048
1049         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1050         if(vid.support.glshaderversion >= 140)
1051         {
1052                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1053                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1054                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1055                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1056                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1057                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1058         }
1059         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1060         else if(vid.support.glshaderversion >= 130)
1061         {
1062                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1063                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1064                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1065                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1066                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1067                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1068         }
1069         // if we can do #version 120, we should (this adds the invariant keyword)
1070         else if(vid.support.glshaderversion >= 120)
1071         {
1072                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1073                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1074                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1075                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1076                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1077                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1078         }
1079         // GLES also adds several things from GLSL120
1080         switch(vid.renderpath)
1081         {
1082         case RENDERPATH_GLES2:
1083                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1084                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1085                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1086                 break;
1087         default:
1088                 break;
1089         }
1090
1091         // the first pretext is which type of shader to compile as
1092         // (later these will all be bound together as a program object)
1093         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1094         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1095         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1096
1097         // the second pretext is the mode (for example a light source)
1098         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1099         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1100         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1101         dp_strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1102
1103         // now add all the permutation pretexts
1104         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1105         {
1106                 if (permutation & (1ll<<i))
1107                 {
1108                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1109                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1110                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1111                         dp_strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1112                 }
1113                 else
1114                 {
1115                         // keep line numbers correct
1116                         vertstrings_list[vertstrings_count++] = "\n";
1117                         geomstrings_list[geomstrings_count++] = "\n";
1118                         fragstrings_list[fragstrings_count++] = "\n";
1119                 }
1120         }
1121
1122         // add static parms
1123         R_CompileShader_AddStaticParms(mode, permutation);
1124         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1125         vertstrings_count += shaderstaticparms_count;
1126         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1127         geomstrings_count += shaderstaticparms_count;
1128         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1129         fragstrings_count += shaderstaticparms_count;
1130
1131         // now append the shader text itself
1132         vertstrings_list[vertstrings_count++] = sourcestring;
1133         geomstrings_list[geomstrings_count++] = sourcestring;
1134         fragstrings_list[fragstrings_count++] = sourcestring;
1135
1136         // we don't currently use geometry shaders for anything, so just empty the list
1137         geomstrings_count = 0;
1138
1139         // compile the shader program
1140         if (vertstrings_count + geomstrings_count + fragstrings_count)
1141                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1142         if (p->program)
1143         {
1144                 CHECKGLERROR
1145                 qglUseProgram(p->program);CHECKGLERROR
1146                 // look up all the uniform variable names we care about, so we don't
1147                 // have to look them up every time we set them
1148
1149 #if 0
1150                 // debugging aid
1151                 {
1152                         GLint activeuniformindex = 0;
1153                         GLint numactiveuniforms = 0;
1154                         char uniformname[128];
1155                         GLsizei uniformnamelength = 0;
1156                         GLint uniformsize = 0;
1157                         GLenum uniformtype = 0;
1158                         memset(uniformname, 0, sizeof(uniformname));
1159                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1160                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1161                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1162                         {
1163                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1164                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1165                         }
1166                 }
1167 #endif
1168
1169                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1170                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1171                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1172                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1173                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1174                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1175                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1176                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1177                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1178                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1179                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1180                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1181                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1182                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1183                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1184                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1185                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1186                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1187                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1188                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1189                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1190                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1191                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1192                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1193                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1194                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1195                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1196                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1197                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1198                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1199                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1200                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1201                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1202                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1203                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1204                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1205                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1206                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1207                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1208                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1209                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1210                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1211                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1212                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1213                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1214                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1215                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1216                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1217                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1218                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1219                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1220                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1221                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1222                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1223                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1224                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1225                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1226                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1227                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1228                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1229                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1230                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1231                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1232                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1233                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1234                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1235                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1236                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1237                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1238                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1239                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1240                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1241                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1242                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1243                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1244                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1245                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1246                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1247                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1248                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1249                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1250                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1251                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1252                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1253                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1254                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1255                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1256                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1257                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1258                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1259                 // initialize the samplers to refer to the texture units we use
1260                 p->tex_Texture_First = -1;
1261                 p->tex_Texture_Second = -1;
1262                 p->tex_Texture_GammaRamps = -1;
1263                 p->tex_Texture_Normal = -1;
1264                 p->tex_Texture_Color = -1;
1265                 p->tex_Texture_Gloss = -1;
1266                 p->tex_Texture_Glow = -1;
1267                 p->tex_Texture_SecondaryNormal = -1;
1268                 p->tex_Texture_SecondaryColor = -1;
1269                 p->tex_Texture_SecondaryGloss = -1;
1270                 p->tex_Texture_SecondaryGlow = -1;
1271                 p->tex_Texture_Pants = -1;
1272                 p->tex_Texture_Shirt = -1;
1273                 p->tex_Texture_FogHeightTexture = -1;
1274                 p->tex_Texture_FogMask = -1;
1275                 p->tex_Texture_LightGrid = -1;
1276                 p->tex_Texture_Lightmap = -1;
1277                 p->tex_Texture_Deluxemap = -1;
1278                 p->tex_Texture_Attenuation = -1;
1279                 p->tex_Texture_Cube = -1;
1280                 p->tex_Texture_Refraction = -1;
1281                 p->tex_Texture_Reflection = -1;
1282                 p->tex_Texture_ShadowMap2D = -1;
1283                 p->tex_Texture_CubeProjection = -1;
1284                 p->tex_Texture_ScreenNormalMap = -1;
1285                 p->tex_Texture_ScreenDiffuse = -1;
1286                 p->tex_Texture_ScreenSpecular = -1;
1287                 p->tex_Texture_ReflectMask = -1;
1288                 p->tex_Texture_ReflectCube = -1;
1289                 p->tex_Texture_BounceGrid = -1;
1290                 // bind the texture samplers in use
1291                 sampler = 0;
1292                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1293                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1294                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1295                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1296                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1297                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1298                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1299                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1300                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1301                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1302                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1303                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1304                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1305                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1306                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1307                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1308                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1309                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1310                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1311                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1312                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1313                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1314                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1315                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1316                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1317                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1318                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1319                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1320                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1321                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1322                 // get the uniform block indices so we can bind them
1323                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1324 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1325                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1326 #endif
1327                 // clear the uniform block bindings
1328                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1329                 // bind the uniform blocks in use
1330                 ubibind = 0;
1331 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1332                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1333 #endif
1334                 // we're done compiling and setting up the shader, at least until it is used
1335                 CHECKGLERROR
1336                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1337         }
1338         else
1339                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1340
1341         // free the strings
1342         if (sourcestring)
1343                 Mem_Free(sourcestring);
1344 }
1345
1346 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1347 {
1348         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1349         if (r_glsl_permutation != perm)
1350         {
1351                 r_glsl_permutation = perm;
1352                 if (!r_glsl_permutation->program)
1353                 {
1354                         if (!r_glsl_permutation->compiled)
1355                         {
1356                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1357                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1358                         }
1359                         if (!r_glsl_permutation->program)
1360                         {
1361                                 // remove features until we find a valid permutation
1362                                 unsigned i;
1363                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1364                                 {
1365                                         // reduce i more quickly whenever it would not remove any bits
1366                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1367                                         if (!(permutation & j))
1368                                                 continue;
1369                                         permutation -= j;
1370                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1371                                         if (!r_glsl_permutation->compiled)
1372                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1373                                         if (r_glsl_permutation->program)
1374                                                 break;
1375                                 }
1376                                 if (i >= SHADERPERMUTATION_COUNT)
1377                                 {
1378                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1379                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1380                                         qglUseProgram(0);CHECKGLERROR
1381                                         return; // no bit left to clear, entire mode is broken
1382                                 }
1383                         }
1384                 }
1385                 CHECKGLERROR
1386                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1387         }
1388         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1389         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1390         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1391         CHECKGLERROR
1392 }
1393
1394 void R_GLSL_Restart_f(cmd_state_t *cmd)
1395 {
1396         unsigned int i, limit;
1397         switch(vid.renderpath)
1398         {
1399         case RENDERPATH_GL32:
1400         case RENDERPATH_GLES2:
1401                 {
1402                         r_glsl_permutation_t *p;
1403                         r_glsl_permutation = NULL;
1404                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1405                         for (i = 0;i < limit;i++)
1406                         {
1407                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1408                                 {
1409                                         GL_Backend_FreeProgram(p->program);
1410                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1411                                 }
1412                         }
1413                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1414                 }
1415                 break;
1416         }
1417 }
1418
1419 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1420 {
1421         unsigned i, language, mode, dupe;
1422         char *text;
1423         shadermodeinfo_t *modeinfo;
1424         qfile_t *file;
1425
1426         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1427         {
1428                 modeinfo = shadermodeinfo[language];
1429                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1430                 {
1431                         // don't dump the same file multiple times (most or all shaders come from the same file)
1432                         for (dupe = mode - 1;dupe >= 0;dupe--)
1433                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1434                                         break;
1435                         if (dupe >= 0)
1436                                 continue;
1437                         text = modeinfo[mode].builtinstring;
1438                         if (!text)
1439                                 continue;
1440                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1441                         if (file)
1442                         {
1443                                 FS_Print(file, "/* The engine may define the following macros:\n");
1444                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1445                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1446                                         FS_Print(file, modeinfo[i].pretext);
1447                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1448                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1449                                 FS_Print(file, "*/\n");
1450                                 FS_Print(file, text);
1451                                 FS_Close(file);
1452                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1453                         }
1454                         else
1455                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1456                 }
1457         }
1458 }
1459
1460 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1461 {
1462         uint64_t permutation = 0;
1463         if (r_trippy.integer && !notrippy)
1464                 permutation |= SHADERPERMUTATION_TRIPPY;
1465         permutation |= SHADERPERMUTATION_VIEWTINT;
1466         if (t)
1467                 permutation |= SHADERPERMUTATION_DIFFUSE;
1468         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1469                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1470         if (suppresstexalpha)
1471                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1472         if (vid.allowalphatocoverage)
1473                 GL_AlphaToCoverage(false);
1474         switch (vid.renderpath)
1475         {
1476         case RENDERPATH_GL32:
1477         case RENDERPATH_GLES2:
1478                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1479                 if (r_glsl_permutation->tex_Texture_First >= 0)
1480                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1481                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1482                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1483                 break;
1484         }
1485 }
1486
1487 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1488 {
1489         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1490 }
1491
1492 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1493 {
1494         uint64_t permutation = 0;
1495         if (r_trippy.integer && !notrippy)
1496                 permutation |= SHADERPERMUTATION_TRIPPY;
1497         if (depthrgb)
1498                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1499         if (skeletal)
1500                 permutation |= SHADERPERMUTATION_SKELETAL;
1501
1502         if (vid.allowalphatocoverage)
1503                 GL_AlphaToCoverage(false);
1504         switch (vid.renderpath)
1505         {
1506         case RENDERPATH_GL32:
1507         case RENDERPATH_GLES2:
1508                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1509 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1510                 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);
1511 #endif
1512                 break;
1513         }
1514 }
1515
1516 #define BLENDFUNC_ALLOWS_COLORMOD      1
1517 #define BLENDFUNC_ALLOWS_FOG           2
1518 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1519 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1520 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1521 static int R_BlendFuncFlags(int src, int dst)
1522 {
1523         int r = 0;
1524
1525         // a blendfunc allows colormod if:
1526         // a) it can never keep the destination pixel invariant, or
1527         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1528         // this is to prevent unintended side effects from colormod
1529
1530         // a blendfunc allows fog if:
1531         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1532         // this is to prevent unintended side effects from fog
1533
1534         // these checks are the output of fogeval.pl
1535
1536         r |= BLENDFUNC_ALLOWS_COLORMOD;
1537         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1538         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1539         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1540         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1541         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1542         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1544         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1545         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1546         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1547         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1548         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1549         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1550         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1551         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1552         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1553         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1554         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1557         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1558
1559         return r;
1560 }
1561
1562 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qbool notrippy, qbool ui)
1563 {
1564         // select a permutation of the lighting shader appropriate to this
1565         // combination of texture, entity, light source, and fogging, only use the
1566         // minimum features necessary to avoid wasting rendering time in the
1567         // fragment shader on features that are not being used
1568         uint64_t permutation = 0;
1569         unsigned int mode = 0;
1570         int blendfuncflags;
1571         texture_t *t = rsurface.texture;
1572         float m16f[16];
1573         matrix4x4_t tempmatrix;
1574         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1575         if (r_trippy.integer && !notrippy)
1576                 permutation |= SHADERPERMUTATION_TRIPPY;
1577         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1578                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1579         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1580                 permutation |= SHADERPERMUTATION_OCCLUDE;
1581         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1582                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1583         if (rsurfacepass == RSURFPASS_BACKGROUND)
1584         {
1585                 // distorted background
1586                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1587                 {
1588                         mode = SHADERMODE_WATER;
1589                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1590                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1591                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1592                         {
1593                                 // this is the right thing to do for wateralpha
1594                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1595                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1596                         }
1597                         else
1598                         {
1599                                 // this is the right thing to do for entity alpha
1600                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1601                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1602                         }
1603                 }
1604                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1605                 {
1606                         mode = SHADERMODE_REFRACTION;
1607                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1608                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1609                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1610                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1611                 }
1612                 else
1613                 {
1614                         mode = SHADERMODE_GENERIC;
1615                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
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                 if (vid.allowalphatocoverage)
1620                         GL_AlphaToCoverage(false);
1621         }
1622         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1623         {
1624                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1625                 {
1626                         switch(t->offsetmapping)
1627                         {
1628                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1629                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1630                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1631                         case OFFSETMAPPING_OFF: break;
1632                         }
1633                 }
1634                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1635                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1636                 // normalmap (deferred prepass), may use alpha test on diffuse
1637                 mode = SHADERMODE_DEFERREDGEOMETRY;
1638                 GL_BlendFunc(GL_ONE, GL_ZERO);
1639                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1640                 if (vid.allowalphatocoverage)
1641                         GL_AlphaToCoverage(false);
1642         }
1643         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1644         {
1645                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1646                 {
1647                         switch(t->offsetmapping)
1648                         {
1649                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1650                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1651                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1652                         case OFFSETMAPPING_OFF: break;
1653                         }
1654                 }
1655                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1656                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1657                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1658                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1659                 // light source
1660                 mode = SHADERMODE_LIGHTSOURCE;
1661                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1662                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1663                 if (VectorLength2(rtlightdiffuse) > 0)
1664                         permutation |= SHADERPERMUTATION_DIFFUSE;
1665                 if (VectorLength2(rtlightspecular) > 0)
1666                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1667                 if (r_refdef.fogenabled)
1668                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1669                 if (t->colormapping)
1670                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1671                 if (r_shadow_usingshadowmap2d)
1672                 {
1673                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1674                         if(r_shadow_shadowmapvsdct)
1675                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1676
1677                         if (r_shadow_shadowmap2ddepthbuffer)
1678                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1679                 }
1680                 if (t->reflectmasktexture)
1681                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1682                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1683                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1684                 if (vid.allowalphatocoverage)
1685                         GL_AlphaToCoverage(false);
1686         }
1687         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1688         {
1689                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1690                 {
1691                         switch(t->offsetmapping)
1692                         {
1693                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1694                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1695                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1696                         case OFFSETMAPPING_OFF: break;
1697                         }
1698                 }
1699                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1700                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1701                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1702                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1703                 // directional model lighting
1704                 mode = SHADERMODE_LIGHTGRID;
1705                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1706                         permutation |= SHADERPERMUTATION_GLOW;
1707                 permutation |= SHADERPERMUTATION_DIFFUSE;
1708                 if (t->glosstexture || t->backgroundglosstexture)
1709                         permutation |= SHADERPERMUTATION_SPECULAR;
1710                 if (r_refdef.fogenabled)
1711                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1712                 if (t->colormapping)
1713                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1714                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1715                 {
1716                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1717                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1718
1719                         if (r_shadow_shadowmap2ddepthbuffer)
1720                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1721                 }
1722                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1723                         permutation |= SHADERPERMUTATION_REFLECTION;
1724                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1725                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1726                 if (t->reflectmasktexture)
1727                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1728                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1729                 {
1730                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1731                         if (r_shadow_bouncegrid_state.directional)
1732                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1733                 }
1734                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1735                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1736                 // when using alphatocoverage, we don't need alphakill
1737                 if (vid.allowalphatocoverage)
1738                 {
1739                         if (r_transparent_alphatocoverage.integer)
1740                         {
1741                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1742                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1743                         }
1744                         else
1745                                 GL_AlphaToCoverage(false);
1746                 }
1747         }
1748         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1749         {
1750                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1751                 {
1752                         switch(t->offsetmapping)
1753                         {
1754                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1755                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1756                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1757                         case OFFSETMAPPING_OFF: break;
1758                         }
1759                 }
1760                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1761                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1762                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1763                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1764                 // directional model lighting
1765                 mode = SHADERMODE_LIGHTDIRECTION;
1766                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1767                         permutation |= SHADERPERMUTATION_GLOW;
1768                 if (VectorLength2(t->render_modellight_diffuse))
1769                         permutation |= SHADERPERMUTATION_DIFFUSE;
1770                 if (VectorLength2(t->render_modellight_specular) > 0)
1771                         permutation |= SHADERPERMUTATION_SPECULAR;
1772                 if (r_refdef.fogenabled)
1773                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1774                 if (t->colormapping)
1775                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1776                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1777                 {
1778                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1779                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1780
1781                         if (r_shadow_shadowmap2ddepthbuffer)
1782                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1783                 }
1784                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1785                         permutation |= SHADERPERMUTATION_REFLECTION;
1786                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1787                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1788                 if (t->reflectmasktexture)
1789                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1790                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1791                 {
1792                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1793                         if (r_shadow_bouncegrid_state.directional)
1794                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1795                 }
1796                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1797                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1798                 // when using alphatocoverage, we don't need alphakill
1799                 if (vid.allowalphatocoverage)
1800                 {
1801                         if (r_transparent_alphatocoverage.integer)
1802                         {
1803                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1804                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1805                         }
1806                         else
1807                                 GL_AlphaToCoverage(false);
1808                 }
1809         }
1810         else
1811         {
1812                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1813                 {
1814                         switch(t->offsetmapping)
1815                         {
1816                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1817                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1818                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1819                         case OFFSETMAPPING_OFF: break;
1820                         }
1821                 }
1822                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1823                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1824                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1825                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1826                 // lightmapped wall
1827                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1828                         permutation |= SHADERPERMUTATION_GLOW;
1829                 if (r_refdef.fogenabled && !ui)
1830                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1831                 if (t->colormapping)
1832                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1833                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1834                 {
1835                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1836                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1837
1838                         if (r_shadow_shadowmap2ddepthbuffer)
1839                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1840                 }
1841                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1842                         permutation |= SHADERPERMUTATION_REFLECTION;
1843                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1844                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1845                 if (t->reflectmasktexture)
1846                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1847                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1848                 {
1849                         // deluxemapping (light direction texture)
1850                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1851                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1852                         else
1853                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1854                         permutation |= SHADERPERMUTATION_DIFFUSE;
1855                         if (VectorLength2(t->render_lightmap_specular) > 0)
1856                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1857                 }
1858                 else if (r_glsl_deluxemapping.integer >= 2)
1859                 {
1860                         // fake deluxemapping (uniform light direction in tangentspace)
1861                         if (rsurface.uselightmaptexture)
1862                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1863                         else
1864                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1865                         permutation |= SHADERPERMUTATION_DIFFUSE;
1866                         if (VectorLength2(t->render_lightmap_specular) > 0)
1867                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1868                 }
1869                 else if (rsurface.uselightmaptexture)
1870                 {
1871                         // ordinary lightmapping (q1bsp, q3bsp)
1872                         mode = SHADERMODE_LIGHTMAP;
1873                 }
1874                 else
1875                 {
1876                         // ordinary vertex coloring (q3bsp)
1877                         mode = SHADERMODE_VERTEXCOLOR;
1878                 }
1879                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1880                 {
1881                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1882                         if (r_shadow_bouncegrid_state.directional)
1883                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1884                 }
1885                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1886                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1887                 // when using alphatocoverage, we don't need alphakill
1888                 if (vid.allowalphatocoverage)
1889                 {
1890                         if (r_transparent_alphatocoverage.integer)
1891                         {
1892                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1893                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1894                         }
1895                         else
1896                                 GL_AlphaToCoverage(false);
1897                 }
1898         }
1899         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1900                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1901         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1902                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1903         switch(vid.renderpath)
1904         {
1905         case RENDERPATH_GL32:
1906         case RENDERPATH_GLES2:
1907                 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);
1908                 RSurf_UploadBuffersForBatch();
1909                 // this has to be after RSurf_PrepareVerticesForBatch
1910                 if (rsurface.batchskeletaltransform3x4buffer)
1911                         permutation |= SHADERPERMUTATION_SKELETAL;
1912                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1913 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1914                 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);
1915 #endif
1916                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1917                 if (mode == SHADERMODE_LIGHTSOURCE)
1918                 {
1919                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1920                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1921                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1922                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1923                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1924                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1925
1926                         // additive passes are only darkened by fog, not tinted
1927                         if (r_glsl_permutation->loc_FogColor >= 0)
1928                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1929                         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);
1930                 }
1931                 else
1932                 {
1933                         if (mode == SHADERMODE_FLATCOLOR)
1934                         {
1935                                 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]);
1936                         }
1937                         else if (mode == SHADERMODE_LIGHTGRID)
1938                         {
1939                                 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]);
1940                                 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]);
1941                                 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]);
1942                                 // other LightGrid uniforms handled below
1943                         }
1944                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1945                         {
1946                                 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]);
1947                                 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]);
1948                                 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]);
1949                                 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]);
1950                                 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]);
1951                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1952                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir_local[0], t->render_modellight_lightdir_local[1], t->render_modellight_lightdir_local[2]);
1953                         }
1954                         else
1955                         {
1956                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1957                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1958                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1959                                 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]);
1960                                 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]);
1961                         }
1962                         // additive passes are only darkened by fog, not tinted
1963                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1964                         {
1965                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1966                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1967                                 else
1968                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1969                         }
1970                         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);
1971                         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]);
1972                         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]);
1973                         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);
1974                         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);
1975                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1976                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1977                         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);
1978                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1979                 }
1980                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1981                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1982                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1983                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1984                 {
1985                         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]);
1986                         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]);
1987                 }
1988                 else
1989                 {
1990                         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]);
1991                         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]);
1992                 }
1993
1994                 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]);
1995                 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));
1996                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1997                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1998                 {
1999                         if (t->pantstexture)
2000                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2001                         else
2002                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2003                 }
2004                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2005                 {
2006                         if (t->shirttexture)
2007                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2008                         else
2009                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2010                 }
2011                 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]);
2012                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2013                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2014                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2015                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2016                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2017                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2018                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2019                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2020                         );
2021                 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);
2022                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2023                 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]);
2024                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2025                 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);}
2026                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2027                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2028                 {
2029                         float m9f[9];
2030                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2031                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2032                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2033                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2034                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2035                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2036                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2037                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2038                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2039                 }
2040
2041                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2042                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2043                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2044                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2045                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2046                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2047                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2048                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2049                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2050                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2051                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2052                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2053                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2054                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2055                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2056                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2057                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2058                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2059                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2060                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2061                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2062                 {
2063                         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);
2064                         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);
2065                         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);
2066                 }
2067                 else
2068                 {
2069                         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);
2070                 }
2071                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2072                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2073                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2074                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2075                 {
2076                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2077                         if (rsurface.rtlight)
2078                         {
2079                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2080                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2081                         }
2082                 }
2083                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2084                 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);
2085                 CHECKGLERROR
2086                 break;
2087         }
2088 }
2089
2090 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2091 {
2092         // select a permutation of the lighting shader appropriate to this
2093         // combination of texture, entity, light source, and fogging, only use the
2094         // minimum features necessary to avoid wasting rendering time in the
2095         // fragment shader on features that are not being used
2096         uint64_t permutation = 0;
2097         unsigned int mode = 0;
2098         const float *lightcolorbase = rtlight->currentcolor;
2099         float ambientscale = rtlight->ambientscale;
2100         float diffusescale = rtlight->diffusescale;
2101         float specularscale = rtlight->specularscale;
2102         // this is the location of the light in view space
2103         vec3_t viewlightorigin;
2104         // this transforms from view space (camera) to light space (cubemap)
2105         matrix4x4_t viewtolight;
2106         matrix4x4_t lighttoview;
2107         float viewtolight16f[16];
2108         // light source
2109         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2110         if (rtlight->currentcubemap != r_texture_whitecube)
2111                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2112         if (diffusescale > 0)
2113                 permutation |= SHADERPERMUTATION_DIFFUSE;
2114         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2115                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2116         if (r_shadow_usingshadowmap2d)
2117         {
2118                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2119                 if (r_shadow_shadowmapvsdct)
2120                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2121
2122                 if (r_shadow_shadowmap2ddepthbuffer)
2123                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2124         }
2125         if (vid.allowalphatocoverage)
2126                 GL_AlphaToCoverage(false);
2127         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2128         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2129         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2130         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2131         switch(vid.renderpath)
2132         {
2133         case RENDERPATH_GL32:
2134         case RENDERPATH_GLES2:
2135                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2136                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2137                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2138                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2139                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2140                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2141                 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]);
2142                 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]);
2143                 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);
2144                 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]);
2145                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2146
2147                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2148                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2149                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2150                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2151                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2152                 break;
2153         }
2154 }
2155
2156 #define SKINFRAME_HASH 1024
2157
2158 typedef struct
2159 {
2160         unsigned int loadsequence; // incremented each level change
2161         memexpandablearray_t array;
2162         skinframe_t *hash[SKINFRAME_HASH];
2163 }
2164 r_skinframe_t;
2165 r_skinframe_t r_skinframe;
2166
2167 void R_SkinFrame_PrepareForPurge(void)
2168 {
2169         r_skinframe.loadsequence++;
2170         // wrap it without hitting zero
2171         if (r_skinframe.loadsequence >= 200)
2172                 r_skinframe.loadsequence = 1;
2173 }
2174
2175 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2176 {
2177         if (!skinframe)
2178                 return;
2179         // mark the skinframe as used for the purging code
2180         skinframe->loadsequence = r_skinframe.loadsequence;
2181 }
2182
2183 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2184 {
2185         if (s == NULL)
2186                 return;
2187         if (s->merged == s->base)
2188                 s->merged = NULL;
2189         R_PurgeTexture(s->stain); s->stain = NULL;
2190         R_PurgeTexture(s->merged); s->merged = NULL;
2191         R_PurgeTexture(s->base); s->base = NULL;
2192         R_PurgeTexture(s->pants); s->pants = NULL;
2193         R_PurgeTexture(s->shirt); s->shirt = NULL;
2194         R_PurgeTexture(s->nmap); s->nmap = NULL;
2195         R_PurgeTexture(s->gloss); s->gloss = NULL;
2196         R_PurgeTexture(s->glow); s->glow = NULL;
2197         R_PurgeTexture(s->fog); s->fog = NULL;
2198         R_PurgeTexture(s->reflect); s->reflect = NULL;
2199         s->loadsequence = 0;
2200 }
2201
2202 void R_SkinFrame_Purge(void)
2203 {
2204         int i;
2205         skinframe_t *s;
2206         for (i = 0;i < SKINFRAME_HASH;i++)
2207         {
2208                 for (s = r_skinframe.hash[i];s;s = s->next)
2209                 {
2210                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2211                                 R_SkinFrame_PurgeSkinFrame(s);
2212                 }
2213         }
2214 }
2215
2216 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2217         skinframe_t *item;
2218         char basename[MAX_QPATH];
2219
2220         Image_StripImageExtension(name, basename, sizeof(basename));
2221
2222         if( last == NULL ) {
2223                 int hashindex;
2224                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2225                 item = r_skinframe.hash[hashindex];
2226         } else {
2227                 item = last->next;
2228         }
2229
2230         // linearly search through the hash bucket
2231         for( ; item ; item = item->next ) {
2232                 if( !strcmp( item->basename, basename ) ) {
2233                         return item;
2234                 }
2235         }
2236         return NULL;
2237 }
2238
2239 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2240 {
2241         skinframe_t *item;
2242         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2243         int hashindex;
2244         char basename[MAX_QPATH];
2245
2246         Image_StripImageExtension(name, basename, sizeof(basename));
2247
2248         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2249         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2250                 if (!strcmp(item->basename, basename) &&
2251                         item->textureflags == compareflags &&
2252                         item->comparewidth == comparewidth &&
2253                         item->compareheight == compareheight &&
2254                         item->comparecrc == comparecrc)
2255                         break;
2256
2257         if (!item)
2258         {
2259                 if (!add)
2260                         return NULL;
2261                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2262                 memset(item, 0, sizeof(*item));
2263                 dp_strlcpy(item->basename, basename, sizeof(item->basename));
2264                 item->textureflags = compareflags;
2265                 item->comparewidth = comparewidth;
2266                 item->compareheight = compareheight;
2267                 item->comparecrc = comparecrc;
2268                 item->next = r_skinframe.hash[hashindex];
2269                 r_skinframe.hash[hashindex] = item;
2270         }
2271         else if (textureflags & TEXF_FORCE_RELOAD)
2272                 R_SkinFrame_PurgeSkinFrame(item);
2273
2274         R_SkinFrame_MarkUsed(item);
2275         return item;
2276 }
2277
2278 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2279         { \
2280                 unsigned long long avgcolor[5], wsum; \
2281                 int pix, comp, w; \
2282                 avgcolor[0] = 0; \
2283                 avgcolor[1] = 0; \
2284                 avgcolor[2] = 0; \
2285                 avgcolor[3] = 0; \
2286                 avgcolor[4] = 0; \
2287                 wsum = 0; \
2288                 for(pix = 0; pix < cnt; ++pix) \
2289                 { \
2290                         w = 0; \
2291                         for(comp = 0; comp < 3; ++comp) \
2292                                 w += getpixel; \
2293                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2294                         { \
2295                                 ++wsum; \
2296                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2297                                 w = getpixel; \
2298                                 for(comp = 0; comp < 3; ++comp) \
2299                                         avgcolor[comp] += getpixel * w; \
2300                                 avgcolor[3] += w; \
2301                         } \
2302                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2303                         avgcolor[4] += getpixel; \
2304                 } \
2305                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2306                         avgcolor[3] = 1; \
2307                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2308                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2309                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2310                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2311         }
2312
2313 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2314 {
2315         skinframe_t *skinframe;
2316
2317         if (cls.state == ca_dedicated)
2318                 return NULL;
2319
2320         // return an existing skinframe if already loaded
2321         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2322         if (skinframe && skinframe->base)
2323                 return skinframe;
2324
2325         // if the skinframe doesn't exist this will create it
2326         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2327 }
2328
2329 extern cvar_t gl_picmip;
2330 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2331 {
2332         int j;
2333         unsigned char *pixels;
2334         unsigned char *bumppixels;
2335         unsigned char *basepixels = NULL;
2336         int basepixels_width = 0;
2337         int basepixels_height = 0;
2338         rtexture_t *ddsbase = NULL;
2339         qbool ddshasalpha = false;
2340         float ddsavgcolor[4];
2341         char basename[MAX_QPATH];
2342         int miplevel = R_PicmipForFlags(textureflags);
2343         int savemiplevel = miplevel;
2344         int mymiplevel;
2345         char vabuf[1024];
2346
2347         if (cls.state == ca_dedicated)
2348                 return NULL;
2349
2350         Image_StripImageExtension(name, basename, sizeof(basename));
2351
2352         // check for DDS texture file first
2353         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2354         {
2355                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2356                 if (basepixels == NULL && fallbacknotexture)
2357                         basepixels = Image_GenerateNoTexture();
2358                 if (basepixels == NULL)
2359                         return NULL;
2360         }
2361
2362         // FIXME handle miplevel
2363
2364         if (developer_loading.integer)
2365                 Con_Printf("loading skin \"%s\"\n", name);
2366
2367         // we've got some pixels to store, so really allocate this new texture now
2368         if (!skinframe)
2369                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2370         textureflags &= ~TEXF_FORCE_RELOAD;
2371         skinframe->stain = NULL;
2372         skinframe->merged = NULL;
2373         skinframe->base = NULL;
2374         skinframe->pants = NULL;
2375         skinframe->shirt = NULL;
2376         skinframe->nmap = NULL;
2377         skinframe->gloss = NULL;
2378         skinframe->glow = NULL;
2379         skinframe->fog = NULL;
2380         skinframe->reflect = NULL;
2381         skinframe->hasalpha = false;
2382         // we could store the q2animname here too
2383
2384         if (ddsbase)
2385         {
2386                 skinframe->base = ddsbase;
2387                 skinframe->hasalpha = ddshasalpha;
2388                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2389                 if (r_loadfog && skinframe->hasalpha)
2390                         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);
2391                 //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]);
2392         }
2393         else
2394         {
2395                 basepixels_width = image_width;
2396                 basepixels_height = image_height;
2397                 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);
2398                 if (textureflags & TEXF_ALPHA)
2399                 {
2400                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2401                         {
2402                                 if (basepixels[j] < 255)
2403                                 {
2404                                         skinframe->hasalpha = true;
2405                                         break;
2406                                 }
2407                         }
2408                         if (r_loadfog && skinframe->hasalpha)
2409                         {
2410                                 // has transparent pixels
2411                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2412                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2413                                 {
2414                                         pixels[j+0] = 255;
2415                                         pixels[j+1] = 255;
2416                                         pixels[j+2] = 255;
2417                                         pixels[j+3] = basepixels[j+3];
2418                                 }
2419                                 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);
2420                                 Mem_Free(pixels);
2421                         }
2422                 }
2423                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2424 #ifndef USE_GLES2
2425                 //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]);
2426                 if (r_savedds && skinframe->base)
2427                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2428                 if (r_savedds && skinframe->fog)
2429                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2430 #endif
2431         }
2432
2433         if (r_loaddds)
2434         {
2435                 mymiplevel = savemiplevel;
2436                 if (r_loadnormalmap)
2437                         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);
2438                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2439                 if (r_loadgloss)
2440                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2441                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2442                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2443                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2444         }
2445
2446         // _norm is the name used by tenebrae and has been adopted as standard
2447         if (r_loadnormalmap && skinframe->nmap == NULL)
2448         {
2449                 mymiplevel = savemiplevel;
2450                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2451                 {
2452                         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);
2453                         Mem_Free(pixels);
2454                         pixels = NULL;
2455                 }
2456                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2457                 {
2458                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2459                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2460                         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);
2461                         Mem_Free(pixels);
2462                         Mem_Free(bumppixels);
2463                 }
2464                 else if (r_shadow_bumpscale_basetexture.value > 0)
2465                 {
2466                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2467                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2468                         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);
2469                         Mem_Free(pixels);
2470                 }
2471 #ifndef USE_GLES2
2472                 if (r_savedds && skinframe->nmap)
2473                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2474 #endif
2475         }
2476
2477         // _luma is supported only for tenebrae compatibility
2478         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2479         // _glow is the preferred name
2480         mymiplevel = savemiplevel;
2481         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))))
2482         {
2483                 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);
2484 #ifndef USE_GLES2
2485                 if (r_savedds && skinframe->glow)
2486                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2487 #endif
2488                 Mem_Free(pixels);pixels = NULL;
2489         }
2490
2491         mymiplevel = savemiplevel;
2492         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2493         {
2494                 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);
2495 #ifndef USE_GLES2
2496                 if (r_savedds && skinframe->gloss)
2497                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2498 #endif
2499                 Mem_Free(pixels);
2500                 pixels = NULL;
2501         }
2502
2503         mymiplevel = savemiplevel;
2504         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2505         {
2506                 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);
2507 #ifndef USE_GLES2
2508                 if (r_savedds && skinframe->pants)
2509                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2510 #endif
2511                 Mem_Free(pixels);
2512                 pixels = NULL;
2513         }
2514
2515         mymiplevel = savemiplevel;
2516         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2517         {
2518                 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);
2519 #ifndef USE_GLES2
2520                 if (r_savedds && skinframe->shirt)
2521                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2522 #endif
2523                 Mem_Free(pixels);
2524                 pixels = NULL;
2525         }
2526
2527         mymiplevel = savemiplevel;
2528         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2529         {
2530                 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);
2531 #ifndef USE_GLES2
2532                 if (r_savedds && skinframe->reflect)
2533                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2534 #endif
2535                 Mem_Free(pixels);
2536                 pixels = NULL;
2537         }
2538
2539         if (basepixels)
2540                 Mem_Free(basepixels);
2541
2542         return skinframe;
2543 }
2544
2545 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qbool sRGB)
2546 {
2547         int i;
2548         skinframe_t *skinframe;
2549         char vabuf[1024];
2550
2551         if (cls.state == ca_dedicated)
2552                 return NULL;
2553
2554         // if already loaded just return it, otherwise make a new skinframe
2555         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2556         if (skinframe->base)
2557                 return skinframe;
2558         textureflags &= ~TEXF_FORCE_RELOAD;
2559
2560         skinframe->stain = NULL;
2561         skinframe->merged = NULL;
2562         skinframe->base = NULL;
2563         skinframe->pants = NULL;
2564         skinframe->shirt = NULL;
2565         skinframe->nmap = NULL;
2566         skinframe->gloss = NULL;
2567         skinframe->glow = NULL;
2568         skinframe->fog = NULL;
2569         skinframe->reflect = NULL;
2570         skinframe->hasalpha = false;
2571
2572         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2573         if (!skindata)
2574                 return NULL;
2575
2576         if (developer_loading.integer)
2577                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2578
2579         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2580         {
2581                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2582                 unsigned char *b = a + width * height * 4;
2583                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2584                 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);
2585                 Mem_Free(a);
2586         }
2587         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2588         if (textureflags & TEXF_ALPHA)
2589         {
2590                 for (i = 3;i < width * height * 4;i += 4)
2591                 {
2592                         if (skindata[i] < 255)
2593                         {
2594                                 skinframe->hasalpha = true;
2595                                 break;
2596                         }
2597                 }
2598                 if (r_loadfog && skinframe->hasalpha)
2599                 {
2600                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2601                         memcpy(fogpixels, skindata, width * height * 4);
2602                         for (i = 0;i < width * height * 4;i += 4)
2603                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2604                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2605                         Mem_Free(fogpixels);
2606                 }
2607         }
2608
2609         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2610         //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]);
2611
2612         return skinframe;
2613 }
2614
2615 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2616 {
2617         int i;
2618         int featuresmask;
2619         skinframe_t *skinframe;
2620
2621         if (cls.state == ca_dedicated)
2622                 return NULL;
2623
2624         // if already loaded just return it, otherwise make a new skinframe
2625         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2626         if (skinframe->base)
2627                 return skinframe;
2628         //textureflags &= ~TEXF_FORCE_RELOAD;
2629
2630         skinframe->stain = NULL;
2631         skinframe->merged = NULL;
2632         skinframe->base = NULL;
2633         skinframe->pants = NULL;
2634         skinframe->shirt = NULL;
2635         skinframe->nmap = NULL;
2636         skinframe->gloss = NULL;
2637         skinframe->glow = NULL;
2638         skinframe->fog = NULL;
2639         skinframe->reflect = NULL;
2640         skinframe->hasalpha = false;
2641
2642         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2643         if (!skindata)
2644                 return NULL;
2645
2646         if (developer_loading.integer)
2647                 Con_Printf("loading quake skin \"%s\"\n", name);
2648
2649         // 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)
2650         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2651         memcpy(skinframe->qpixels, skindata, width*height);
2652         skinframe->qwidth = width;
2653         skinframe->qheight = height;
2654
2655         featuresmask = 0;
2656         for (i = 0;i < width * height;i++)
2657                 featuresmask |= palette_featureflags[skindata[i]];
2658
2659         skinframe->hasalpha = false;
2660         // fence textures
2661         if (name[0] == '{')
2662                 skinframe->hasalpha = true;
2663         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2664         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2665         skinframe->qgeneratemerged = true;
2666         skinframe->qgeneratebase = skinframe->qhascolormapping;
2667         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2668
2669         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2670         //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]);
2671
2672         return skinframe;
2673 }
2674
2675 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2676 {
2677         int width;
2678         int height;
2679         unsigned char *skindata;
2680         char vabuf[1024];
2681
2682         if (!skinframe->qpixels)
2683                 return;
2684
2685         if (!skinframe->qhascolormapping)
2686                 colormapped = false;
2687
2688         if (colormapped)
2689         {
2690                 if (!skinframe->qgeneratebase)
2691                         return;
2692         }
2693         else
2694         {
2695                 if (!skinframe->qgeneratemerged)
2696                         return;
2697         }
2698
2699         width = skinframe->qwidth;
2700         height = skinframe->qheight;
2701         skindata = skinframe->qpixels;
2702
2703         if (skinframe->qgeneratenmap)
2704         {
2705                 unsigned char *a, *b;
2706                 skinframe->qgeneratenmap = false;
2707                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2708                 b = a + width * height * 4;
2709                 // use either a custom palette or the quake palette
2710                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2711                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2712                 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);
2713                 Mem_Free(a);
2714         }
2715
2716         if (skinframe->qgenerateglow)
2717         {
2718                 skinframe->qgenerateglow = false;
2719                 if (skinframe->hasalpha) // fence textures
2720                         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
2721                 else
2722                         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
2723         }
2724
2725         if (colormapped)
2726         {
2727                 skinframe->qgeneratebase = false;
2728                 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);
2729                 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);
2730                 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);
2731         }
2732         else
2733         {
2734                 skinframe->qgeneratemerged = false;
2735                 if (skinframe->hasalpha) // fence textures
2736                         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);
2737                 else
2738                         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);
2739         }
2740
2741         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2742         {
2743                 Mem_Free(skinframe->qpixels);
2744                 skinframe->qpixels = NULL;
2745         }
2746 }
2747
2748 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)
2749 {
2750         int i;
2751         skinframe_t *skinframe;
2752         char vabuf[1024];
2753
2754         if (cls.state == ca_dedicated)
2755                 return NULL;
2756
2757         // if already loaded just return it, otherwise make a new skinframe
2758         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2759         if (skinframe->base)
2760                 return skinframe;
2761         textureflags &= ~TEXF_FORCE_RELOAD;
2762
2763         skinframe->stain = NULL;
2764         skinframe->merged = NULL;
2765         skinframe->base = NULL;
2766         skinframe->pants = NULL;
2767         skinframe->shirt = NULL;
2768         skinframe->nmap = NULL;
2769         skinframe->gloss = NULL;
2770         skinframe->glow = NULL;
2771         skinframe->fog = NULL;
2772         skinframe->reflect = NULL;
2773         skinframe->hasalpha = false;
2774
2775         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2776         if (!skindata)
2777                 return NULL;
2778
2779         if (developer_loading.integer)
2780                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2781
2782         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2783         if ((textureflags & TEXF_ALPHA) && alphapalette)
2784         {
2785                 for (i = 0;i < width * height;i++)
2786                 {
2787                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2788                         {
2789                                 skinframe->hasalpha = true;
2790                                 break;
2791                         }
2792                 }
2793                 if (r_loadfog && skinframe->hasalpha)
2794                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2795         }
2796
2797         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2798         //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]);
2799
2800         return skinframe;
2801 }
2802
2803 skinframe_t *R_SkinFrame_LoadMissing(void)
2804 {
2805         skinframe_t *skinframe;
2806
2807         if (cls.state == ca_dedicated)
2808                 return NULL;
2809
2810         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2811         skinframe->stain = NULL;
2812         skinframe->merged = NULL;
2813         skinframe->base = NULL;
2814         skinframe->pants = NULL;
2815         skinframe->shirt = NULL;
2816         skinframe->nmap = NULL;
2817         skinframe->gloss = NULL;
2818         skinframe->glow = NULL;
2819         skinframe->fog = NULL;
2820         skinframe->reflect = NULL;
2821         skinframe->hasalpha = false;
2822
2823         skinframe->avgcolor[0] = rand() / RAND_MAX;
2824         skinframe->avgcolor[1] = rand() / RAND_MAX;
2825         skinframe->avgcolor[2] = rand() / RAND_MAX;
2826         skinframe->avgcolor[3] = 1;
2827
2828         return skinframe;
2829 }
2830
2831 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2832 {
2833         if (cls.state == ca_dedicated)
2834                 return NULL;
2835
2836         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2837 }
2838
2839 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2840 {
2841         skinframe_t *skinframe;
2842         if (cls.state == ca_dedicated)
2843                 return NULL;
2844         // if already loaded just return it, otherwise make a new skinframe
2845         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2846         if (skinframe->base)
2847                 return skinframe;
2848         textureflags &= ~TEXF_FORCE_RELOAD;
2849         skinframe->stain = NULL;
2850         skinframe->merged = NULL;
2851         skinframe->base = NULL;
2852         skinframe->pants = NULL;
2853         skinframe->shirt = NULL;
2854         skinframe->nmap = NULL;
2855         skinframe->gloss = NULL;
2856         skinframe->glow = NULL;
2857         skinframe->fog = NULL;
2858         skinframe->reflect = NULL;
2859         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2860         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2861         if (!tex)
2862                 return NULL;
2863         if (developer_loading.integer)
2864                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2865         skinframe->base = skinframe->merged = tex;
2866         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2867         return skinframe;
2868 }
2869
2870 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2871 typedef struct suffixinfo_s
2872 {
2873         const char *suffix;
2874         qbool flipx, flipy, flipdiagonal;
2875 }
2876 suffixinfo_t;
2877 static suffixinfo_t suffix[3][6] =
2878 {
2879         {
2880                 {"px",   false, false, false},
2881                 {"nx",   false, false, false},
2882                 {"py",   false, false, false},
2883                 {"ny",   false, false, false},
2884                 {"pz",   false, false, false},
2885                 {"nz",   false, false, false}
2886         },
2887         {
2888                 {"posx", false, false, false},
2889                 {"negx", false, false, false},
2890                 {"posy", false, false, false},
2891                 {"negy", false, false, false},
2892                 {"posz", false, false, false},
2893                 {"negz", false, false, false}
2894         },
2895         {
2896                 {"rt",    true, false,  true},
2897                 {"lf",   false,  true,  true},
2898                 {"ft",    true,  true, false},
2899                 {"bk",   false, false, false},
2900                 {"up",    true, false,  true},
2901                 {"dn",    true, false,  true}
2902         }
2903 };
2904
2905 static int componentorder[4] = {0, 1, 2, 3};
2906
2907 static rtexture_t *R_LoadCubemap(const char *basename)
2908 {
2909         int i, j, cubemapsize, forcefilter;
2910         unsigned char *cubemappixels, *image_buffer;
2911         rtexture_t *cubemaptexture;
2912         char name[256];
2913
2914         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2915         forcefilter = TEXF_FORCELINEAR;
2916         if (basename && basename[0] == '!')
2917         {
2918                 basename++;
2919                 forcefilter = TEXF_FORCENEAREST;
2920         }
2921         // must start 0 so the first loadimagepixels has no requested width/height
2922         cubemapsize = 0;
2923         cubemappixels = NULL;
2924         cubemaptexture = NULL;
2925         // keep trying different suffix groups (posx, px, rt) until one loads
2926         for (j = 0;j < 3 && !cubemappixels;j++)
2927         {
2928                 // load the 6 images in the suffix group
2929                 for (i = 0;i < 6;i++)
2930                 {
2931                         // generate an image name based on the base and and suffix
2932                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2933                         // load it
2934                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2935                         {
2936                                 // an image loaded, make sure width and height are equal
2937                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2938                                 {
2939                                         // if this is the first image to load successfully, allocate the cubemap memory
2940                                         if (!cubemappixels && image_width >= 1)
2941                                         {
2942                                                 cubemapsize = image_width;
2943                                                 // note this clears to black, so unavailable sides are black
2944                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2945                                         }
2946                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2947                                         if (cubemappixels)
2948                                                 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);
2949                                 }
2950                                 else
2951                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2952                                 // free the image
2953                                 Mem_Free(image_buffer);
2954                         }
2955                 }
2956         }
2957         // if a cubemap loaded, upload it
2958         if (cubemappixels)
2959         {
2960                 if (developer_loading.integer)
2961                         Con_Printf("loading cubemap \"%s\"\n", basename);
2962
2963                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | forcefilter | TEXF_CLAMP, -1, NULL);
2964                 Mem_Free(cubemappixels);
2965         }
2966         else
2967         {
2968                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2969                 if (developer_loading.integer)
2970                 {
2971                         Con_Printf("(tried tried images ");
2972                         for (j = 0;j < 3;j++)
2973                                 for (i = 0;i < 6;i++)
2974                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2975                         Con_Print(" and was unable to find any of them).\n");
2976                 }
2977         }
2978         return cubemaptexture;
2979 }
2980
2981 rtexture_t *R_GetCubemap(const char *basename)
2982 {
2983         int i;
2984         for (i = 0;i < r_texture_numcubemaps;i++)
2985                 if (r_texture_cubemaps[i] != NULL)
2986                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2987                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2988         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2989                 return r_texture_whitecube;
2990         r_texture_numcubemaps++;
2991         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2992         dp_strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2993         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2994         return r_texture_cubemaps[i]->texture;
2995 }
2996
2997 static void R_Main_FreeViewCache(void)
2998 {
2999         if (r_refdef.viewcache.entityvisible)
3000                 Mem_Free(r_refdef.viewcache.entityvisible);
3001         if (r_refdef.viewcache.world_pvsbits)
3002                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3003         if (r_refdef.viewcache.world_leafvisible)
3004                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3005         if (r_refdef.viewcache.world_surfacevisible)
3006                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3007         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3008 }
3009
3010 static void R_Main_ResizeViewCache(void)
3011 {
3012         int numentities = r_refdef.scene.numentities;
3013         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3014         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3015         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3016         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3017         if (r_refdef.viewcache.maxentities < numentities)
3018         {
3019                 r_refdef.viewcache.maxentities = numentities;
3020                 if (r_refdef.viewcache.entityvisible)
3021                         Mem_Free(r_refdef.viewcache.entityvisible);
3022                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3023         }
3024         if (r_refdef.viewcache.world_numclusters != numclusters)
3025         {
3026                 r_refdef.viewcache.world_numclusters = numclusters;
3027                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3028                 if (r_refdef.viewcache.world_pvsbits)
3029                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3030                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3031         }
3032         if (r_refdef.viewcache.world_numleafs != numleafs)
3033         {
3034                 r_refdef.viewcache.world_numleafs = numleafs;
3035                 if (r_refdef.viewcache.world_leafvisible)
3036                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3037                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3038         }
3039         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3040         {
3041                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3042                 if (r_refdef.viewcache.world_surfacevisible)
3043                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3044                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3045         }
3046 }
3047
3048 extern rtexture_t *loadingscreentexture;
3049 static void gl_main_start(void)
3050 {
3051         loadingscreentexture = NULL;
3052         r_texture_blanknormalmap = NULL;
3053         r_texture_white = NULL;
3054         r_texture_grey128 = NULL;
3055         r_texture_black = NULL;
3056         r_texture_whitecube = NULL;
3057         r_texture_normalizationcube = NULL;
3058         r_texture_fogattenuation = NULL;
3059         r_texture_fogheighttexture = NULL;
3060         r_texture_gammaramps = NULL;
3061         r_texture_numcubemaps = 0;
3062         r_uniformbufferalignment = 32;
3063
3064         r_loaddds = r_texture_dds_load.integer != 0;
3065         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3066
3067         switch(vid.renderpath)
3068         {
3069         case RENDERPATH_GL32:
3070         case RENDERPATH_GLES2:
3071                 r_loadnormalmap = true;
3072                 r_loadgloss = true;
3073                 r_loadfog = false;
3074 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3075                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3076 #endif
3077                 break;
3078         }
3079
3080         R_AnimCache_Free();
3081         R_FrameData_Reset();
3082         R_BufferData_Reset();
3083
3084         r_numqueries = 0;
3085         r_maxqueries = 0;
3086         memset(r_queries, 0, sizeof(r_queries));
3087
3088         r_qwskincache = NULL;
3089         r_qwskincache_size = 0;
3090
3091         // due to caching of texture_t references, the collision cache must be reset
3092         Collision_Cache_Reset(true);
3093
3094         // set up r_skinframe loading system for textures
3095         memset(&r_skinframe, 0, sizeof(r_skinframe));
3096         r_skinframe.loadsequence = 1;
3097         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3098
3099         r_main_texturepool = R_AllocTexturePool();
3100         R_BuildBlankTextures();
3101         R_BuildNoTexture();
3102         R_BuildWhiteCube();
3103 #ifndef USE_GLES2
3104         R_BuildNormalizationCube();
3105 #endif //USE_GLES2
3106         r_texture_fogattenuation = NULL;
3107         r_texture_fogheighttexture = NULL;
3108         r_texture_gammaramps = NULL;
3109         //r_texture_fogintensity = NULL;
3110         memset(&r_fb, 0, sizeof(r_fb));
3111         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3112         r_glsl_permutation = NULL;
3113         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3114         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3115         memset(&r_svbsp, 0, sizeof (r_svbsp));
3116
3117         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3118         r_texture_numcubemaps = 0;
3119
3120         r_refdef.fogmasktable_density = 0;
3121
3122 #ifdef __ANDROID__
3123         // For Steelstorm Android
3124         // FIXME CACHE the program and reload
3125         // FIXME see possible combinations for SS:BR android
3126         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3127         R_SetupShader_SetPermutationGLSL(0, 12);
3128         R_SetupShader_SetPermutationGLSL(0, 13);
3129         R_SetupShader_SetPermutationGLSL(0, 8388621);
3130         R_SetupShader_SetPermutationGLSL(3, 0);
3131         R_SetupShader_SetPermutationGLSL(3, 2048);
3132         R_SetupShader_SetPermutationGLSL(5, 0);
3133         R_SetupShader_SetPermutationGLSL(5, 2);
3134         R_SetupShader_SetPermutationGLSL(5, 2048);
3135         R_SetupShader_SetPermutationGLSL(5, 8388608);
3136         R_SetupShader_SetPermutationGLSL(11, 1);
3137         R_SetupShader_SetPermutationGLSL(11, 2049);
3138         R_SetupShader_SetPermutationGLSL(11, 8193);
3139         R_SetupShader_SetPermutationGLSL(11, 10241);
3140         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3141 #endif
3142 }
3143
3144 extern unsigned int r_shadow_occlusion_buf;
3145
3146 static void gl_main_shutdown(void)
3147 {
3148         R_RenderTarget_FreeUnused(true);
3149         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3150         R_AnimCache_Free();
3151         R_FrameData_Reset();
3152         R_BufferData_Reset();
3153
3154         R_Main_FreeViewCache();
3155
3156         switch(vid.renderpath)
3157         {
3158         case RENDERPATH_GL32:
3159         case RENDERPATH_GLES2:
3160 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3161                 if (r_maxqueries)
3162                         qglDeleteQueries(r_maxqueries, r_queries);
3163 #endif
3164                 break;
3165         }
3166         r_shadow_occlusion_buf = 0;
3167         r_numqueries = 0;
3168         r_maxqueries = 0;
3169         memset(r_queries, 0, sizeof(r_queries));
3170
3171         r_qwskincache = NULL;
3172         r_qwskincache_size = 0;
3173
3174         // clear out the r_skinframe state
3175         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3176         memset(&r_skinframe, 0, sizeof(r_skinframe));
3177
3178         if (r_svbsp.nodes)
3179                 Mem_Free(r_svbsp.nodes);
3180         memset(&r_svbsp, 0, sizeof (r_svbsp));
3181         R_FreeTexturePool(&r_main_texturepool);
3182         loadingscreentexture = NULL;
3183         r_texture_blanknormalmap = NULL;
3184         r_texture_white = NULL;
3185         r_texture_grey128 = NULL;
3186         r_texture_black = NULL;
3187         r_texture_whitecube = NULL;
3188         r_texture_normalizationcube = NULL;
3189         r_texture_fogattenuation = NULL;
3190         r_texture_fogheighttexture = NULL;
3191         r_texture_gammaramps = NULL;
3192         r_texture_numcubemaps = 0;
3193         //r_texture_fogintensity = NULL;
3194         memset(&r_fb, 0, sizeof(r_fb));
3195         R_GLSL_Restart_f(cmd_local);
3196
3197         r_glsl_permutation = NULL;
3198         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3199         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3200 }
3201
3202 static void gl_main_newmap(void)
3203 {
3204         // FIXME: move this code to client
3205         char *entities, entname[MAX_QPATH];
3206         if (r_qwskincache)
3207                 Mem_Free(r_qwskincache);
3208         r_qwskincache = NULL;
3209         r_qwskincache_size = 0;
3210         if (cl.worldmodel)
3211         {
3212                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3213                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3214                 {
3215                         CL_ParseEntityLump(entities);
3216                         Mem_Free(entities);
3217                         return;
3218                 }
3219                 if (cl.worldmodel->brush.entities)
3220                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3221         }
3222         R_Main_FreeViewCache();
3223
3224         R_FrameData_Reset();
3225         R_BufferData_Reset();
3226 }
3227
3228 void GL_Main_Init(void)
3229 {
3230         int i;
3231         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3232         R_InitShaderModeInfo();
3233
3234         Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3235         Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3236         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3237         if (gamemode == GAME_NEHAHRA)
3238         {
3239                 Cvar_RegisterVariable (&gl_fogenable);
3240                 Cvar_RegisterVariable (&gl_fogdensity);
3241                 Cvar_RegisterVariable (&gl_fogred);
3242                 Cvar_RegisterVariable (&gl_foggreen);
3243                 Cvar_RegisterVariable (&gl_fogblue);
3244                 Cvar_RegisterVariable (&gl_fogstart);
3245                 Cvar_RegisterVariable (&gl_fogend);
3246                 Cvar_RegisterVariable (&gl_skyclip);
3247         }
3248         Cvar_RegisterVariable(&r_motionblur);
3249         Cvar_RegisterVariable(&r_damageblur);
3250         Cvar_RegisterVariable(&r_motionblur_averaging);
3251         Cvar_RegisterVariable(&r_motionblur_randomize);
3252         Cvar_RegisterVariable(&r_motionblur_minblur);
3253         Cvar_RegisterVariable(&r_motionblur_maxblur);
3254         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3255         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3256         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3257         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3258         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3259         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3260         Cvar_RegisterVariable(&r_depthfirst);
3261         Cvar_RegisterVariable(&r_useinfinitefarclip);
3262         Cvar_RegisterVariable(&r_farclip_base);
3263         Cvar_RegisterVariable(&r_farclip_world);
3264         Cvar_RegisterVariable(&r_nearclip);
3265         Cvar_RegisterVariable(&r_deformvertexes);
3266         Cvar_RegisterVariable(&r_transparent);
3267         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3268         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3269         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3270         Cvar_RegisterVariable(&r_showoverdraw);
3271         Cvar_RegisterVariable(&r_showbboxes);
3272         Cvar_RegisterVariable(&r_showbboxes_client);
3273         Cvar_RegisterVariable(&r_showsurfaces);
3274         Cvar_RegisterVariable(&r_showtris);
3275         Cvar_RegisterVariable(&r_shownormals);
3276         Cvar_RegisterVariable(&r_showlighting);
3277         Cvar_RegisterVariable(&r_showcollisionbrushes);
3278         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3279         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3280         Cvar_RegisterVariable(&r_showdisabledepthtest);
3281         Cvar_RegisterVariable(&r_showspriteedges);
3282         Cvar_RegisterVariable(&r_showparticleedges);
3283         Cvar_RegisterVariable(&r_drawportals);
3284         Cvar_RegisterVariable(&r_drawentities);
3285         Cvar_RegisterVariable(&r_draw2d);
3286         Cvar_RegisterVariable(&r_drawworld);
3287         Cvar_RegisterVariable(&r_cullentities_trace);
3288         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3289         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3290         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3291         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3292         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3293         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3294         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3295         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3296         Cvar_RegisterVariable(&r_sortentities);
3297         Cvar_RegisterVariable(&r_drawviewmodel);
3298         Cvar_RegisterVariable(&r_drawexteriormodel);
3299         Cvar_RegisterVariable(&r_speeds);
3300         Cvar_RegisterVariable(&r_fullbrights);
3301         Cvar_RegisterVariable(&r_wateralpha);
3302         Cvar_RegisterVariable(&r_dynamic);
3303         Cvar_RegisterVariable(&r_fullbright_directed);
3304         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3305         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3306         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3307         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3308         Cvar_RegisterVariable(&r_fullbright);
3309         Cvar_RegisterVariable(&r_shadows);
3310         Cvar_RegisterVariable(&r_shadows_darken);
3311         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3312         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3313         Cvar_RegisterVariable(&r_shadows_throwdistance);
3314         Cvar_RegisterVariable(&r_shadows_throwdirection);
3315         Cvar_RegisterVariable(&r_shadows_focus);
3316         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3317         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3318         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3319         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3320         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3321         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3322         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3323         Cvar_RegisterVariable(&r_fog_exp2);
3324         Cvar_RegisterVariable(&r_fog_clear);
3325         Cvar_RegisterVariable(&r_drawfog);
3326         Cvar_RegisterVariable(&r_transparentdepthmasking);
3327         Cvar_RegisterVariable(&r_transparent_sortmindist);
3328         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3329         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3330         Cvar_RegisterVariable(&r_texture_dds_load);
3331         Cvar_RegisterVariable(&r_texture_dds_save);
3332         Cvar_RegisterVariable(&r_usedepthtextures);
3333         Cvar_RegisterVariable(&r_viewfbo);
3334         Cvar_RegisterVariable(&r_rendertarget_debug);
3335         Cvar_RegisterVariable(&r_viewscale);
3336         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3337         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3338         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3339         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3340         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3341         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3342         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3343         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3344         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3345         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3346         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3347         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3348         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3349         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3350         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3351         Cvar_RegisterVariable(&r_glsl_postprocess);
3352         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3353         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3354         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3355         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3356         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3357         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3358         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3359         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3360         Cvar_RegisterVariable(&r_celshading);
3361         Cvar_RegisterVariable(&r_celoutlines);
3362         Cvar_RegisterVariable(&r_fxaa);
3363
3364         Cvar_RegisterVariable(&r_water);
3365         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3366         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3367         Cvar_RegisterVariable(&r_water_clippingplanebias);
3368         Cvar_RegisterVariable(&r_water_refractdistort);
3369         Cvar_RegisterVariable(&r_water_reflectdistort);
3370         Cvar_RegisterVariable(&r_water_scissormode);
3371         Cvar_RegisterVariable(&r_water_lowquality);
3372         Cvar_RegisterVariable(&r_water_hideplayer);
3373
3374         Cvar_RegisterVariable(&r_lerpsprites);
3375         Cvar_RegisterVariable(&r_lerpmodels);
3376         Cvar_RegisterVariable(&r_nolerp_list);
3377         Cvar_RegisterVariable(&r_lerplightstyles);
3378         Cvar_RegisterVariable(&r_waterscroll);
3379         Cvar_RegisterVariable(&r_bloom);
3380         Cvar_RegisterVariable(&r_colorfringe);
3381         Cvar_RegisterVariable(&r_bloom_colorscale);
3382         Cvar_RegisterVariable(&r_bloom_brighten);
3383         Cvar_RegisterVariable(&r_bloom_blur);
3384         Cvar_RegisterVariable(&r_bloom_resolution);
3385         Cvar_RegisterVariable(&r_bloom_colorexponent);
3386         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3387         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3388         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3389         Cvar_RegisterVariable(&r_hdr_glowintensity);
3390         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3391         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3392         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3393         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3394         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3395         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3396         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3397         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3398         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3399         Cvar_RegisterVariable(&developer_texturelogging);
3400         Cvar_RegisterVariable(&gl_lightmaps);
3401         Cvar_RegisterVariable(&r_test);
3402         Cvar_RegisterVariable(&r_batch_multidraw);
3403         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3404         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3405         Cvar_RegisterVariable(&r_glsl_skeletal);
3406         Cvar_RegisterVariable(&r_glsl_saturation);
3407         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3408         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3409         Cvar_RegisterVariable(&r_framedatasize);
3410         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3411                 Cvar_RegisterVariable(&r_buffermegs[i]);
3412         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3413         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3414         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3415         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3416         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3417                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3418 #ifdef DP_MOBILETOUCH
3419         // GLES devices have terrible depth precision in general, so...
3420         Cvar_SetValueQuick(&r_nearclip, 4);
3421         Cvar_SetValueQuick(&r_farclip_base, 4096);
3422         Cvar_SetValueQuick(&r_farclip_world, 0);
3423         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3424 #endif
3425         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3426 }
3427
3428 void Render_Init(void)
3429 {
3430         gl_backend_init();
3431         R_Textures_Init();
3432         GL_Main_Init();
3433         Font_Init();
3434         GL_Draw_Init();
3435         R_Shadow_Init();
3436         R_Sky_Init();
3437         GL_Surf_Init();
3438         Sbar_Init();
3439         R_Particles_Init();
3440         R_Explosion_Init();
3441         R_LightningBeams_Init();
3442         CL_MeshEntities_Init();
3443         Mod_RenderInit();
3444 }
3445
3446 static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits)
3447 {
3448         out[0] = ((signbits & 1) ? mins : maxs)[0];
3449         out[1] = ((signbits & 2) ? mins : maxs)[1];
3450         out[2] = ((signbits & 4) ? mins : maxs)[2];
3451 }
3452
3453 static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore)
3454 {
3455         int i;
3456         const mplane_t *p;
3457         vec3_t corner;
3458         if (r_trippy.integer)
3459                 return false;
3460         for (i = 0;i < numplanes;i++)
3461         {
3462                 if(i == ignore)
3463                         continue;
3464                 p = planes + i;
3465                 R_GetCornerOfBox(corner, mins, maxs, p->signbits);
3466                 if (DotProduct(p->normal, corner) < p->dist)
3467                         return true;
3468         }
3469         return false;
3470 }
3471
3472 qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs)
3473 {
3474         // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
3475         return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4);
3476 }
3477
3478 qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3479 {
3480         // nothing to ignore
3481         return _R_CullBox(mins, maxs, numplanes, planes, -1);
3482 }
3483
3484 //==================================================================================
3485
3486 // LadyHavoc: this stores temporary data used within the same frame
3487
3488 typedef struct r_framedata_mem_s
3489 {
3490         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3491         size_t size; // how much usable space
3492         size_t current; // how much space in use
3493         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3494         size_t wantedsize; // how much space was allocated
3495         unsigned char *data; // start of real data (16byte aligned)
3496 }
3497 r_framedata_mem_t;
3498
3499 static r_framedata_mem_t *r_framedata_mem;
3500
3501 void R_FrameData_Reset(void)
3502 {
3503         while (r_framedata_mem)
3504         {
3505                 r_framedata_mem_t *next = r_framedata_mem->purge;
3506                 Mem_Free(r_framedata_mem);
3507                 r_framedata_mem = next;
3508         }
3509 }
3510
3511 static void R_FrameData_Resize(qbool mustgrow)
3512 {
3513         size_t wantedsize;
3514         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3515         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3516         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3517         {
3518                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3519                 newmem->wantedsize = wantedsize;
3520                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3521                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3522                 newmem->current = 0;
3523                 newmem->mark = 0;
3524                 newmem->purge = r_framedata_mem;
3525                 r_framedata_mem = newmem;
3526         }
3527 }
3528
3529 void R_FrameData_NewFrame(void)
3530 {
3531         R_FrameData_Resize(false);
3532         if (!r_framedata_mem)
3533                 return;
3534         // if we ran out of space on the last frame, free the old memory now
3535         while (r_framedata_mem->purge)
3536         {
3537                 // repeatedly remove the second item in the list, leaving only head
3538                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3539                 Mem_Free(r_framedata_mem->purge);
3540                 r_framedata_mem->purge = next;
3541         }
3542         // reset the current mem pointer
3543         r_framedata_mem->current = 0;
3544         r_framedata_mem->mark = 0;
3545 }
3546
3547 void *R_FrameData_Alloc(size_t size)
3548 {
3549         void *data;
3550         float newvalue;
3551
3552         // align to 16 byte boundary - the data pointer is already aligned, so we
3553         // only need to ensure the size of every allocation is also aligned
3554         size = (size + 15) & ~15;
3555
3556         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3557         {
3558                 // emergency - we ran out of space, allocate more memory
3559                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3560                 newvalue = r_framedatasize.value * 2.0f;
3561                 // 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
3562                 if (sizeof(size_t) >= 8)
3563                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3564                 else
3565                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3566                 // this might not be a growing it, but we'll allocate another buffer every time
3567                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3568                 R_FrameData_Resize(true);
3569         }
3570
3571         data = r_framedata_mem->data + r_framedata_mem->current;
3572         r_framedata_mem->current += size;
3573
3574         // count the usage for stats
3575         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3576         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3577
3578         return (void *)data;
3579 }
3580
3581 void *R_FrameData_Store(size_t size, void *data)
3582 {
3583         void *d = R_FrameData_Alloc(size);
3584         if (d && data)
3585                 memcpy(d, data, size);
3586         return d;
3587 }
3588
3589 void R_FrameData_SetMark(void)
3590 {
3591         if (!r_framedata_mem)
3592                 return;
3593         r_framedata_mem->mark = r_framedata_mem->current;
3594 }
3595
3596 void R_FrameData_ReturnToMark(void)
3597 {
3598         if (!r_framedata_mem)
3599                 return;
3600         r_framedata_mem->current = r_framedata_mem->mark;
3601 }
3602
3603 //==================================================================================
3604
3605 // avoid reusing the same buffer objects on consecutive frames
3606 #define R_BUFFERDATA_CYCLE 3
3607
3608 typedef struct r_bufferdata_buffer_s
3609 {
3610         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3611         size_t size; // how much usable space
3612         size_t current; // how much space in use
3613         r_meshbuffer_t *buffer; // the buffer itself
3614 }
3615 r_bufferdata_buffer_t;
3616
3617 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3618 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3619
3620 /// frees all dynamic buffers
3621 void R_BufferData_Reset(void)
3622 {
3623         int cycle, type;
3624         r_bufferdata_buffer_t **p, *mem;
3625         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3626         {
3627                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3628                 {
3629                         // free all buffers
3630                         p = &r_bufferdata_buffer[cycle][type];
3631                         while (*p)
3632                         {
3633                                 mem = *p;
3634                                 *p = (*p)->purge;
3635                                 if (mem->buffer)
3636                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3637                                 Mem_Free(mem);
3638                         }
3639                 }
3640         }
3641 }
3642
3643 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3644 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3645 {
3646         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3647         size_t size;
3648         float newvalue = r_buffermegs[type].value;
3649
3650         // increase the cvar if we have to (but only if we already have a mem)
3651         if (mustgrow && mem)
3652                 newvalue *= 2.0f;
3653         newvalue = bound(0.25f, newvalue, 256.0f);
3654         while (newvalue * 1024*1024 < minsize)
3655                 newvalue *= 2.0f;
3656
3657         // clamp the cvar to valid range
3658         newvalue = bound(0.25f, newvalue, 256.0f);
3659         if (r_buffermegs[type].value != newvalue)
3660                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3661
3662         // calculate size in bytes
3663         size = (size_t)(newvalue * 1024*1024);
3664         size = bound(131072, size, 256*1024*1024);
3665
3666         // allocate a new buffer if the size is different (purge old one later)
3667         // or if we were told we must grow the buffer
3668         if (!mem || mem->size != size || mustgrow)
3669         {
3670                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3671                 mem->size = size;
3672                 mem->current = 0;
3673                 if (type == R_BUFFERDATA_VERTEX)
3674                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3675                 else if (type == R_BUFFERDATA_INDEX16)
3676                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3677                 else if (type == R_BUFFERDATA_INDEX32)
3678                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3679                 else if (type == R_BUFFERDATA_UNIFORM)
3680                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3681                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3682                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3683         }
3684 }
3685
3686 void R_BufferData_NewFrame(void)
3687 {
3688         int type;
3689         r_bufferdata_buffer_t **p, *mem;
3690         // cycle to the next frame's buffers
3691         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3692         // if we ran out of space on the last time we used these buffers, free the old memory now
3693         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3694         {
3695                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3696                 {
3697                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3698                         // free all but the head buffer, this is how we recycle obsolete
3699                         // buffers after they are no longer in use
3700                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3701                         while (*p)
3702                         {
3703                                 mem = *p;
3704                                 *p = (*p)->purge;
3705                                 if (mem->buffer)
3706                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3707                                 Mem_Free(mem);
3708                         }
3709                         // reset the current offset
3710                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3711                 }
3712         }
3713 }
3714
3715 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3716 {
3717         r_bufferdata_buffer_t *mem;
3718         int offset = 0;
3719         int padsize;
3720
3721         *returnbufferoffset = 0;
3722
3723         // align size to a byte boundary appropriate for the buffer type, this
3724         // makes all allocations have aligned start offsets
3725         if (type == R_BUFFERDATA_UNIFORM)
3726                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3727         else
3728                 padsize = (datasize + 15) & ~15;
3729
3730         // if we ran out of space in this buffer we must allocate a new one
3731         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)
3732                 R_BufferData_Resize(type, true, padsize);
3733
3734         // if the resize did not give us enough memory, fail
3735         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)
3736                 Sys_Abort("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3737
3738         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3739         offset = (int)mem->current;
3740         mem->current += padsize;
3741
3742         // upload the data to the buffer at the chosen offset
3743         if (offset == 0)
3744                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3745         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3746
3747         // count the usage for stats
3748         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3749         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3750
3751         // return the buffer offset
3752         *returnbufferoffset = offset;
3753
3754         return mem->buffer;
3755 }
3756
3757 //==================================================================================
3758
3759 // LadyHavoc: animcache originally written by Echon, rewritten since then
3760
3761 /**
3762  * Animation cache prevents re-generating mesh data for an animated model
3763  * multiple times in one frame for lighting, shadowing, reflections, etc.
3764  */
3765
3766 void R_AnimCache_Free(void)
3767 {
3768 }
3769
3770 void R_AnimCache_ClearCache(void)
3771 {
3772         int i;
3773         entity_render_t *ent;
3774
3775         for (i = 0;i < r_refdef.scene.numentities;i++)
3776         {
3777                 ent = r_refdef.scene.entities[i];
3778                 ent->animcache_vertex3f = NULL;
3779                 ent->animcache_vertex3f_vertexbuffer = NULL;
3780                 ent->animcache_vertex3f_bufferoffset = 0;
3781                 ent->animcache_normal3f = NULL;
3782                 ent->animcache_normal3f_vertexbuffer = NULL;
3783                 ent->animcache_normal3f_bufferoffset = 0;
3784                 ent->animcache_svector3f = NULL;
3785                 ent->animcache_svector3f_vertexbuffer = NULL;
3786                 ent->animcache_svector3f_bufferoffset = 0;
3787                 ent->animcache_tvector3f = NULL;
3788                 ent->animcache_tvector3f_vertexbuffer = NULL;
3789                 ent->animcache_tvector3f_bufferoffset = 0;
3790                 ent->animcache_skeletaltransform3x4 = NULL;
3791                 ent->animcache_skeletaltransform3x4buffer = NULL;
3792                 ent->animcache_skeletaltransform3x4offset = 0;
3793                 ent->animcache_skeletaltransform3x4size = 0;
3794         }
3795 }
3796
3797 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3798 {
3799         model_t *model = ent->model;
3800         int numvertices;
3801
3802         // see if this ent is worth caching
3803         if (!model || !model->Draw || !model->AnimateVertices)
3804                 return false;
3805         // nothing to cache if it contains no animations and has no skeleton
3806         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3807                 return false;
3808         // see if it is already cached for gpuskeletal
3809         if (ent->animcache_skeletaltransform3x4)
3810                 return false;
3811         // see if it is already cached as a mesh
3812         if (ent->animcache_vertex3f)
3813         {
3814                 // check if we need to add normals or tangents
3815                 if (ent->animcache_normal3f)
3816                         wantnormals = false;
3817                 if (ent->animcache_svector3f)
3818                         wanttangents = false;
3819                 if (!wantnormals && !wanttangents)
3820                         return false;
3821         }
3822
3823         // check which kind of cache we need to generate
3824         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3825         {
3826                 // cache the skeleton so the vertex shader can use it
3827                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3828                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3829                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3830                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3831                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3832                 // note: this can fail if the buffer is at the grow limit
3833                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3834                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3835         }
3836         else if (ent->animcache_vertex3f)
3837         {
3838                 // mesh was already cached but we may need to add normals/tangents
3839                 // (this only happens with multiple views, reflections, cameras, etc)
3840                 if (wantnormals || wanttangents)
3841                 {
3842                         numvertices = model->surfmesh.num_vertices;
3843                         if (wantnormals)
3844                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3845                         if (wanttangents)
3846                         {
3847                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3848                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3849                         }
3850                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3851                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3852                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3853                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3854                 }
3855         }
3856         else
3857         {
3858                 // generate mesh cache
3859                 numvertices = model->surfmesh.num_vertices;
3860                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3861                 if (wantnormals)
3862                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3863                 if (wanttangents)
3864                 {
3865                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3866                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3867                 }
3868                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3869                 if (wantnormals || wanttangents)
3870                 {
3871                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3872                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3873                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3874                 }
3875                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3876                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3877                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3878         }
3879         return true;
3880 }
3881
3882 void R_AnimCache_CacheVisibleEntities(void)
3883 {
3884         int i;
3885
3886         // TODO: thread this
3887         // NOTE: R_PrepareRTLights() also caches entities
3888
3889         for (i = 0;i < r_refdef.scene.numentities;i++)
3890                 if (r_refdef.viewcache.entityvisible[i])
3891                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3892 }
3893
3894 //==================================================================================
3895
3896 qbool R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
3897 {
3898         long unsigned int i;
3899         int j;
3900         vec3_t eyemins, eyemaxs;
3901         vec3_t boxmins, boxmaxs;
3902         vec3_t padmins, padmaxs;
3903         vec3_t start;
3904         vec3_t end;
3905         model_t *model = r_refdef.scene.worldmodel;
3906         static vec3_t positions[] = {
3907                 { 0.5f, 0.5f, 0.5f },
3908                 { 0.0f, 0.0f, 0.0f },
3909                 { 0.0f, 0.0f, 1.0f },
3910                 { 0.0f, 1.0f, 0.0f },
3911                 { 0.0f, 1.0f, 1.0f },
3912                 { 1.0f, 0.0f, 0.0f },
3913                 { 1.0f, 0.0f, 1.0f },
3914                 { 1.0f, 1.0f, 0.0f },
3915                 { 1.0f, 1.0f, 1.0f },
3916         };
3917
3918         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3919         if (numsamples < 0)
3920                 return true;
3921
3922         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3923         if (!r_refdef.view.usevieworiginculling)
3924                 return true;
3925
3926         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3927                 return true;
3928
3929         // expand the eye box a little
3930         eyemins[0] = eye[0] - eyejitter;
3931         eyemaxs[0] = eye[0] + eyejitter;
3932         eyemins[1] = eye[1] - eyejitter;
3933         eyemaxs[1] = eye[1] + eyejitter;
3934         eyemins[2] = eye[2] - eyejitter;
3935         eyemaxs[2] = eye[2] + eyejitter;
3936         // expand the box a little
3937         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3938         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3939         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3940         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3941         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3942         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3943         // make an even larger box for the acceptable area
3944         padmins[0] = boxmins[0] - pad;
3945         padmaxs[0] = boxmaxs[0] + pad;
3946         padmins[1] = boxmins[1] - pad;
3947         padmaxs[1] = boxmaxs[1] + pad;
3948         padmins[2] = boxmins[2] - pad;
3949         padmaxs[2] = boxmaxs[2] + pad;
3950
3951         // return true if eye overlaps enlarged box
3952         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3953                 return true;
3954
3955         VectorCopy(eye, start);
3956         // try specific positions in the box first - note that these can be cached
3957         if (r_cullentities_trace_entityocclusion.integer)
3958         {
3959                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3960                 {
3961                         trace_t trace;
3962                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3963                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3964                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3965                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3966                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3967                         // not picky - if the trace ended anywhere in the box we're good
3968                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3969                                 return true;
3970                 }
3971         }
3972         else
3973         {
3974                 // try center
3975                 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
3976                 if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3977                         return true;
3978         }
3979
3980         // try various random positions
3981         for (j = 0; j < numsamples; j++)
3982         {
3983                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3984                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3985                 if (r_cullentities_trace_entityocclusion.integer)
3986                 {
3987                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3988                         // not picky - if the trace ended anywhere in the box we're good
3989                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3990                                 return true;
3991                 }
3992                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3993                         return true;
3994         }
3995
3996         return false;
3997 }
3998
3999
4000 static void R_View_UpdateEntityVisible (void)
4001 {
4002         int i;
4003         int renderimask;
4004         int samples;
4005         entity_render_t *ent;
4006
4007         if (r_refdef.envmap || r_fb.water.hideplayer)
4008                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4009         else if (chase_active.integer || r_fb.water.renderingscene)
4010                 renderimask = RENDER_VIEWMODEL;
4011         else
4012                 renderimask = RENDER_EXTERIORMODEL;
4013         if (!r_drawviewmodel.integer)
4014                 renderimask |= RENDER_VIEWMODEL;
4015         if (!r_drawexteriormodel.integer)
4016                 renderimask |= RENDER_EXTERIORMODEL;
4017         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4018         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4019         {
4020                 // worldmodel can check visibility
4021                 for (i = 0;i < r_refdef.scene.numentities;i++)
4022                 {
4023                         ent = r_refdef.scene.entities[i];
4024                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4025                         {
4026                                 r_refdef.viewcache.entityvisible[i] = false;
4027                                 continue;
4028                         }
4029                         if (!(ent->flags & renderimask))
4030                         if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4031                         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))
4032                                 r_refdef.viewcache.entityvisible[i] = true;
4033                 }
4034         }
4035         else
4036         {
4037                 // no worldmodel or it can't check visibility
4038                 for (i = 0;i < r_refdef.scene.numentities;i++)
4039                 {
4040                         ent = r_refdef.scene.entities[i];
4041                         if (!(ent->flags & renderimask))
4042                         if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4043                                 r_refdef.viewcache.entityvisible[i] = true;
4044                 }
4045         }
4046         if (r_cullentities_trace.integer)
4047         {
4048                 for (i = 0;i < r_refdef.scene.numentities;i++)
4049                 {
4050                         if (!r_refdef.viewcache.entityvisible[i])
4051                                 continue;
4052                         ent = r_refdef.scene.entities[i];
4053                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4054                         {
4055                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4056                                 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))
4057                                         ent->last_trace_visibility = host.realtime;
4058                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4059                                         r_refdef.viewcache.entityvisible[i] = 0;
4060                         }
4061                 }
4062         }
4063 }
4064
4065 /// only used if skyrendermasked, and normally returns false
4066 static int R_DrawBrushModelsSky (void)
4067 {
4068         int i, sky;
4069         entity_render_t *ent;
4070
4071         sky = false;
4072         for (i = 0;i < r_refdef.scene.numentities;i++)
4073         {
4074                 if (!r_refdef.viewcache.entityvisible[i])
4075                         continue;
4076                 ent = r_refdef.scene.entities[i];
4077                 if (!ent->model || !ent->model->DrawSky)
4078                         continue;
4079                 ent->model->DrawSky(ent);
4080                 sky = true;
4081         }
4082         return sky;
4083 }
4084
4085 static void R_DrawNoModel(entity_render_t *ent);
4086 static void R_DrawModels(void)
4087 {
4088         int i;
4089         entity_render_t *ent;
4090
4091         for (i = 0;i < r_refdef.scene.numentities;i++)
4092         {
4093                 if (!r_refdef.viewcache.entityvisible[i])
4094                         continue;
4095                 ent = r_refdef.scene.entities[i];
4096                 r_refdef.stats[r_stat_entities]++;
4097
4098                 if (ent->model && ent->model->Draw != NULL)
4099                         ent->model->Draw(ent);
4100                 else
4101                         R_DrawNoModel(ent);
4102         }
4103 }
4104
4105 static void R_DrawModelsDepth(void)
4106 {
4107         int i;
4108         entity_render_t *ent;
4109
4110         for (i = 0;i < r_refdef.scene.numentities;i++)
4111         {
4112                 if (!r_refdef.viewcache.entityvisible[i])
4113                         continue;
4114                 ent = r_refdef.scene.entities[i];
4115                 if (ent->model && ent->model->DrawDepth != NULL)
4116                         ent->model->DrawDepth(ent);
4117         }
4118 }
4119
4120 static void R_DrawModelsDebug(void)
4121 {
4122         int i;
4123         entity_render_t *ent;
4124
4125         for (i = 0;i < r_refdef.scene.numentities;i++)
4126         {
4127                 if (!r_refdef.viewcache.entityvisible[i])
4128                         continue;
4129                 ent = r_refdef.scene.entities[i];
4130                 if (ent->model && ent->model->DrawDebug != NULL)
4131                         ent->model->DrawDebug(ent);
4132         }
4133 }
4134
4135 static void R_DrawModelsAddWaterPlanes(void)
4136 {
4137         int i;
4138         entity_render_t *ent;
4139
4140         for (i = 0;i < r_refdef.scene.numentities;i++)
4141         {
4142                 if (!r_refdef.viewcache.entityvisible[i])
4143                         continue;
4144                 ent = r_refdef.scene.entities[i];
4145                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4146                         ent->model->DrawAddWaterPlanes(ent);
4147         }
4148 }
4149
4150 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}};
4151
4152 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4153 {
4154         if (r_hdr_irisadaptation.integer)
4155         {
4156                 vec3_t p;
4157                 vec3_t ambient;
4158                 vec3_t diffuse;
4159                 vec3_t diffusenormal;
4160                 vec3_t forward;
4161                 vec_t brightness = 0.0f;
4162                 vec_t goal;
4163                 vec_t current;
4164                 vec_t d;
4165                 int c;
4166                 VectorCopy(r_refdef.view.forward, forward);
4167                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4168                 {
4169                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4170                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4171                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4172                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4173                         d = DotProduct(forward, diffusenormal);
4174                         brightness += VectorLength(ambient);
4175                         if (d > 0)
4176                                 brightness += d * VectorLength(diffuse);
4177                 }
4178                 brightness *= 1.0f / c;
4179                 brightness += 0.00001f; // make sure it's never zero
4180                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4181                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4182                 current = r_hdr_irisadaptation_value.value;
4183                 if (current < goal)
4184                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4185                 else if (current > goal)
4186                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4187                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4188                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4189         }
4190         else if (r_hdr_irisadaptation_value.value != 1.0f)
4191                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4192 }
4193
4194 extern cvar_t r_lockvisibility;
4195 extern cvar_t r_lockpvs;
4196
4197 static void R_View_SetFrustum(const int *scissor)
4198 {
4199         int i;
4200         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4201         vec3_t forward, left, up, origin, v;
4202         if(r_lockvisibility.integer)
4203                 return;
4204         if(scissor)
4205         {
4206                 // flipped x coordinates (because x points left here)
4207                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4208                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4209                 // non-flipped y coordinates
4210                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4211                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4212         }
4213
4214         // we can't trust r_refdef.view.forward and friends in reflected scenes
4215         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4216
4217 #if 0
4218         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4219         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4220         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4221         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4222         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4223         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4224         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4225         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4226         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4227         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4228         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4229         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4230 #endif
4231
4232 #if 0
4233         zNear = r_refdef.nearclip;
4234         nudge = 1.0 - 1.0 / (1<<23);
4235         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4236         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4237         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4238         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4239         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4240         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4241         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4242         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4243 #endif
4244
4245
4246
4247 #if 0
4248         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4249         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4250         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4251         r_refdef.view.frustum[0].dist = m[15] - m[12];
4252
4253         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4254         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4255         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4256         r_refdef.view.frustum[1].dist = m[15] + m[12];
4257
4258         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4259         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4260         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4261         r_refdef.view.frustum[2].dist = m[15] - m[13];
4262
4263         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4264         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4265         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4266         r_refdef.view.frustum[3].dist = m[15] + m[13];
4267
4268         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4269         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4270         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4271         r_refdef.view.frustum[4].dist = m[15] - m[14];
4272
4273         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4274         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4275         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4276         r_refdef.view.frustum[5].dist = m[15] + m[14];
4277 #endif
4278
4279         if (r_refdef.view.useperspective)
4280         {
4281                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4282                 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]);
4283                 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]);
4284                 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]);
4285                 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]);
4286
4287                 // then the normals from the corners relative to origin
4288                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4289                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4290                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4291                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4292
4293                 // in a NORMAL view, forward cross left == up
4294                 // in a REFLECTED view, forward cross left == down
4295                 // so our cross products above need to be adjusted for a left handed coordinate system
4296                 CrossProduct(forward, left, v);
4297                 if(DotProduct(v, up) < 0)
4298                 {
4299                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4300                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4301                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4302                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4303                 }
4304
4305                 // Leaving those out was a mistake, those were in the old code, and they
4306                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4307                 // I couldn't reproduce it after adding those normalizations. --blub
4308                 VectorNormalize(r_refdef.view.frustum[0].normal);
4309                 VectorNormalize(r_refdef.view.frustum[1].normal);
4310                 VectorNormalize(r_refdef.view.frustum[2].normal);
4311                 VectorNormalize(r_refdef.view.frustum[3].normal);
4312
4313                 // make the corners absolute
4314                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4315                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4316                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4317                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4318
4319                 // one more normal
4320                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4321
4322                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4323                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4324                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4325                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4326                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4327         }
4328         else
4329         {
4330                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4331                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4332                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4333                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4334                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4335                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4336                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4337                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4338                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4339                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4340         }
4341         r_refdef.view.numfrustumplanes = 5;
4342
4343         if (r_refdef.view.useclipplane)
4344         {
4345                 r_refdef.view.numfrustumplanes = 6;
4346                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4347         }
4348
4349         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4350                 PlaneClassify(r_refdef.view.frustum + i);
4351
4352         // LadyHavoc: note to all quake engine coders, Quake had a special case
4353         // for 90 degrees which assumed a square view (wrong), so I removed it,
4354         // Quake2 has it disabled as well.
4355
4356         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4357         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4358         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4359         //PlaneClassify(&frustum[0]);
4360
4361         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4362         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4363         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4364         //PlaneClassify(&frustum[1]);
4365
4366         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4367         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4368         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4369         //PlaneClassify(&frustum[2]);
4370
4371         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4372         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4373         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4374         //PlaneClassify(&frustum[3]);
4375
4376         // nearclip plane
4377         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4378         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4379         //PlaneClassify(&frustum[4]);
4380 }
4381
4382 static void R_View_UpdateWithScissor(const int *myscissor)
4383 {
4384         R_Main_ResizeViewCache();
4385         R_View_SetFrustum(myscissor);
4386         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4387         R_View_UpdateEntityVisible();
4388 }
4389
4390 static void R_View_Update(void)
4391 {
4392         R_Main_ResizeViewCache();
4393         R_View_SetFrustum(NULL);
4394         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4395         R_View_UpdateEntityVisible();
4396 }
4397
4398 float viewscalefpsadjusted = 1.0f;
4399
4400 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4401 {
4402         const float *customclipplane = NULL;
4403         float plane[4];
4404         int viewy_adjusted;
4405         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4406         {
4407                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4408                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4409                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4410                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4411                         dist = r_refdef.view.clipplane.dist;
4412                 plane[0] = r_refdef.view.clipplane.normal[0];
4413                 plane[1] = r_refdef.view.clipplane.normal[1];
4414                 plane[2] = r_refdef.view.clipplane.normal[2];
4415                 plane[3] = -dist;
4416                 customclipplane = plane;
4417         }
4418
4419         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
4420         // Unless the render target is a FBO...
4421         viewy_adjusted = viewfbo ? viewy : vid.height - viewheight - viewy;
4422
4423         if (!r_refdef.view.useperspective)
4424                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4425         else if (vid.stencil && r_useinfinitefarclip.integer)
4426                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4427         else
4428                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4429         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4430         R_SetViewport(&r_refdef.view.viewport);
4431 }
4432
4433 void R_EntityMatrix(const matrix4x4_t *matrix)
4434 {
4435         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4436         {
4437                 gl_modelmatrixchanged = false;
4438                 gl_modelmatrix = *matrix;
4439                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4440                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4441                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4442                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4443                 CHECKGLERROR
4444                 switch(vid.renderpath)
4445                 {
4446                 case RENDERPATH_GL32:
4447                 case RENDERPATH_GLES2:
4448                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4449                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4450                         break;
4451                 }
4452         }
4453 }
4454
4455 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4456 {
4457         r_viewport_t viewport;
4458         int viewy_adjusted;
4459
4460         CHECKGLERROR
4461
4462         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
4463         // Unless the render target is a FBO...
4464         viewy_adjusted = viewfbo ? viewy : vid.height - viewheight - viewy;
4465
4466         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, viewy_adjusted, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4467         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4468         R_SetViewport(&viewport);
4469         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4470         GL_Color(1, 1, 1, 1);
4471         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4472         GL_BlendFunc(GL_ONE, GL_ZERO);
4473         GL_ScissorTest(false);
4474         GL_DepthMask(false);
4475         GL_DepthRange(0, 1);
4476         GL_DepthTest(false);
4477         GL_DepthFunc(GL_LEQUAL);
4478         R_EntityMatrix(&identitymatrix);
4479         R_Mesh_ResetTextureState();
4480         GL_PolygonOffset(0, 0);
4481         switch(vid.renderpath)
4482         {
4483         case RENDERPATH_GL32:
4484         case RENDERPATH_GLES2:
4485                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4486                 break;
4487         }
4488         GL_CullFace(GL_NONE);
4489
4490         CHECKGLERROR
4491 }
4492
4493 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4494 {
4495         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4496 }
4497
4498 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4499 {
4500         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4501         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4502         GL_Color(1, 1, 1, 1);
4503         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4504         GL_BlendFunc(GL_ONE, GL_ZERO);
4505         GL_ScissorTest(true);
4506         GL_DepthMask(true);
4507         GL_DepthRange(0, 1);
4508         GL_DepthTest(true);
4509         GL_DepthFunc(GL_LEQUAL);
4510         R_EntityMatrix(&identitymatrix);
4511         R_Mesh_ResetTextureState();
4512         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4513         switch(vid.renderpath)
4514         {
4515         case RENDERPATH_GL32:
4516         case RENDERPATH_GLES2:
4517                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4518                 break;
4519         }
4520         GL_CullFace(r_refdef.view.cullface_back);
4521 }
4522
4523 /*
4524 ================
4525 R_RenderView_UpdateViewVectors
4526 ================
4527 */
4528 void R_RenderView_UpdateViewVectors(void)
4529 {
4530         // break apart the view matrix into vectors for various purposes
4531         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4532         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4533         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4534         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4535         // make an inverted copy of the view matrix for tracking sprites
4536         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4537 }
4538
4539 void R_RenderTarget_FreeUnused(qbool force)
4540 {
4541         unsigned int i, j, end;
4542         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4543         for (i = 0; i < end; i++)
4544         {
4545                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4546                 // free resources for rendertargets that have not been used for a while
4547                 // (note: this check is run after the frame render, so any targets used
4548                 // this frame will not be affected even at low framerates)
4549                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4550                 {
4551                         if (r->fbo)
4552                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4553                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4554                                 if (r->colortexture[j])
4555                                         R_FreeTexture(r->colortexture[j]);
4556                         if (r->depthtexture)
4557                                 R_FreeTexture(r->depthtexture);
4558                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4559                 }
4560         }
4561 }
4562
4563 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4564 {
4565         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4566         x1 = x * iw;
4567         x2 = (x + w) * iw;
4568         y1 = (th - y) * ih;
4569         y2 = (th - y - h) * ih;
4570         texcoord2f[0] = x1;
4571         texcoord2f[2] = x2;
4572         texcoord2f[4] = x2;
4573         texcoord2f[6] = x1;
4574         texcoord2f[1] = y1;
4575         texcoord2f[3] = y1;
4576         texcoord2f[5] = y2;
4577         texcoord2f[7] = y2;
4578 }
4579
4580 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qbool depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4581 {
4582         unsigned int i, j, end;
4583         r_rendertarget_t *r = NULL;
4584         char vabuf[256];
4585         // first try to reuse an existing slot if possible
4586         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4587         for (i = 0; i < end; i++)
4588         {
4589                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4590                 if (r && r->lastusetime != host.realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
4591                         break;
4592         }
4593         if (i == end)
4594         {
4595                 // no unused exact match found, so we have to make one in the first unused slot
4596                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4597                 r->texturewidth = texturewidth;
4598                 r->textureheight = textureheight;
4599                 r->colortextype[0] = colortextype0;
4600                 r->colortextype[1] = colortextype1;
4601                 r->colortextype[2] = colortextype2;
4602                 r->colortextype[3] = colortextype3;
4603                 r->depthtextype = depthtextype;
4604                 r->depthisrenderbuffer = depthisrenderbuffer;
4605                 for (j = 0; j < 4; j++)
4606                         if (r->colortextype[j])
4607                                 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);
4608                 if (r->depthtextype)
4609                 {
4610                         if (r->depthisrenderbuffer)
4611                                 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);
4612                         else
4613                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4614                 }
4615                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4616         }
4617         r_refdef.stats[r_stat_rendertargets_used]++;
4618         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4619         r->lastusetime = host.realtime;
4620         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4621         return r;
4622 }
4623
4624 static void R_Water_StartFrame(int viewwidth, int viewheight)
4625 {
4626         int waterwidth, waterheight;
4627
4628         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4629                 return;
4630
4631         // set waterwidth and waterheight to the water resolution that will be
4632         // used (often less than the screen resolution for faster rendering)
4633         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4634         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4635
4636         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4637                 waterwidth = waterheight = 0;
4638
4639         // set up variables that will be used in shader setup
4640         r_fb.water.waterwidth = waterwidth;
4641         r_fb.water.waterheight = waterheight;
4642         r_fb.water.texturewidth = waterwidth;
4643         r_fb.water.textureheight = waterheight;
4644         r_fb.water.camerawidth = waterwidth;
4645         r_fb.water.cameraheight = waterheight;
4646         r_fb.water.screenscale[0] = 0.5f;
4647         r_fb.water.screenscale[1] = 0.5f;
4648         r_fb.water.screencenter[0] = 0.5f;
4649         r_fb.water.screencenter[1] = 0.5f;
4650         r_fb.water.enabled = waterwidth != 0;
4651
4652         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4653         r_fb.water.numwaterplanes = 0;
4654 }
4655
4656 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4657 {
4658         int planeindex, bestplaneindex, vertexindex;
4659         vec3_t mins, maxs, normal, center, v, n;
4660         vec_t planescore, bestplanescore;
4661         mplane_t plane;
4662         r_waterstate_waterplane_t *p;
4663         texture_t *t = R_GetCurrentTexture(surface->texture);
4664
4665         rsurface.texture = t;
4666         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4667         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4668         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4669                 return;
4670         // average the vertex normals, find the surface bounds (after deformvertexes)
4671         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4672         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4673         VectorCopy(n, normal);
4674         VectorCopy(v, mins);
4675         VectorCopy(v, maxs);
4676         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4677         {
4678                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4679                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4680                 VectorAdd(normal, n, normal);
4681                 mins[0] = min(mins[0], v[0]);
4682                 mins[1] = min(mins[1], v[1]);
4683                 mins[2] = min(mins[2], v[2]);
4684                 maxs[0] = max(maxs[0], v[0]);
4685                 maxs[1] = max(maxs[1], v[1]);
4686                 maxs[2] = max(maxs[2], v[2]);
4687         }
4688         VectorNormalize(normal);
4689         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4690
4691         VectorCopy(normal, plane.normal);
4692         VectorNormalize(plane.normal);
4693         plane.dist = DotProduct(center, plane.normal);
4694         PlaneClassify(&plane);
4695         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4696         {
4697                 // skip backfaces (except if nocullface is set)
4698 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4699 //                      return;
4700                 VectorNegate(plane.normal, plane.normal);
4701                 plane.dist *= -1;
4702                 PlaneClassify(&plane);
4703         }
4704
4705
4706         // find a matching plane if there is one
4707         bestplaneindex = -1;
4708         bestplanescore = 1048576.0f;
4709         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4710         {
4711                 if(p->camera_entity == t->camera_entity)
4712                 {
4713                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4714                         if (bestplaneindex < 0 || bestplanescore > planescore)
4715                         {
4716                                 bestplaneindex = planeindex;
4717                                 bestplanescore = planescore;
4718                         }
4719                 }
4720         }
4721         planeindex = bestplaneindex;
4722
4723         // if this surface does not fit any known plane rendered this frame, add one
4724         if (planeindex < 0 || bestplanescore > 0.001f)
4725         {
4726                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4727                 {
4728                         // store the new plane
4729                         planeindex = r_fb.water.numwaterplanes++;
4730                         p = r_fb.water.waterplanes + planeindex;
4731                         p->plane = plane;
4732                         // clear materialflags and pvs
4733                         p->materialflags = 0;
4734                         p->pvsvalid = false;
4735                         p->camera_entity = t->camera_entity;
4736                         VectorCopy(mins, p->mins);
4737                         VectorCopy(maxs, p->maxs);
4738                 }
4739                 else
4740                 {
4741                         // We're totally screwed.
4742                         return;
4743                 }
4744         }
4745         else
4746         {
4747                 // merge mins/maxs when we're adding this surface to the plane
4748                 p = r_fb.water.waterplanes + planeindex;
4749                 p->mins[0] = min(p->mins[0], mins[0]);
4750                 p->mins[1] = min(p->mins[1], mins[1]);
4751                 p->mins[2] = min(p->mins[2], mins[2]);
4752                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4753                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4754                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4755         }
4756         // merge this surface's materialflags into the waterplane
4757         p->materialflags |= t->currentmaterialflags;
4758         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4759         {
4760                 // merge this surface's PVS into the waterplane
4761                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4762                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4763                 {
4764                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4765                         p->pvsvalid = true;
4766                 }
4767         }
4768 }
4769
4770 extern cvar_t r_drawparticles;
4771 extern cvar_t r_drawdecals;
4772
4773 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4774 {
4775         int myscissor[4];
4776         r_refdef_view_t originalview;
4777         r_refdef_view_t myview;
4778         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;
4779         r_waterstate_waterplane_t *p;
4780         vec3_t visorigin;
4781         r_rendertarget_t *rt;
4782
4783         originalview = r_refdef.view;
4784
4785         // lowquality hack, temporarily shut down some cvars and restore afterwards
4786         qualityreduction = r_water_lowquality.integer;
4787         if (qualityreduction > 0)
4788         {
4789                 if (qualityreduction >= 1)
4790                 {
4791                         old_r_shadows = r_shadows.integer;
4792                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4793                         old_r_dlight = r_shadow_realtime_dlight.integer;
4794                         Cvar_SetValueQuick(&r_shadows, 0);
4795                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4796                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4797                 }
4798                 if (qualityreduction >= 2)
4799                 {
4800                         old_r_dynamic = r_dynamic.integer;
4801                         old_r_particles = r_drawparticles.integer;
4802                         old_r_decals = r_drawdecals.integer;
4803                         Cvar_SetValueQuick(&r_dynamic, 0);
4804                         Cvar_SetValueQuick(&r_drawparticles, 0);
4805                         Cvar_SetValueQuick(&r_drawdecals, 0);
4806                 }
4807         }
4808
4809         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4810         {
4811                 p->rt_reflection = NULL;
4812                 p->rt_refraction = NULL;
4813                 p->rt_camera = NULL;
4814         }
4815
4816         // render views
4817         r_refdef.view = originalview;
4818         r_refdef.view.showdebug = false;
4819         r_refdef.view.width = r_fb.water.waterwidth;
4820         r_refdef.view.height = r_fb.water.waterheight;
4821         r_refdef.view.useclipplane = true;
4822         myview = r_refdef.view;
4823         r_fb.water.renderingscene = true;
4824         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4825         {
4826                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4827                         continue;
4828
4829                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4830                 {
4831                         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);
4832                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4833                                 goto error;
4834                         r_refdef.view = myview;
4835                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4836                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4837                         if(r_water_scissormode.integer)
4838                         {
4839                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4840                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4841                                 {
4842                                         p->rt_reflection = NULL;
4843                                         p->rt_refraction = NULL;
4844                                         p->rt_camera = NULL;
4845                                         continue;
4846                                 }
4847                         }
4848
4849                         r_refdef.view.clipplane = p->plane;
4850                         // reflected view origin may be in solid, so don't cull with it
4851                         r_refdef.view.usevieworiginculling = false;
4852                         // reverse the cullface settings for this render
4853                         r_refdef.view.cullface_front = GL_FRONT;
4854                         r_refdef.view.cullface_back = GL_BACK;
4855                         // combined pvs (based on what can be seen from each surface center)
4856                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4857                         {
4858                                 r_refdef.view.usecustompvs = true;
4859                                 if (p->pvsvalid)
4860                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4861                                 else
4862                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4863                         }
4864
4865                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4866                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4867                         GL_ScissorTest(false);
4868                         R_ClearScreen(r_refdef.fogenabled);
4869                         GL_ScissorTest(true);
4870                         if(r_water_scissormode.integer & 2)
4871                                 R_View_UpdateWithScissor(myscissor);
4872                         else
4873                                 R_View_Update();
4874                         R_AnimCache_CacheVisibleEntities();
4875                         if(r_water_scissormode.integer & 1)
4876                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4877                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4878
4879                         r_fb.water.hideplayer = false;
4880                         p->rt_reflection = rt;
4881                 }
4882
4883                 // render the normal view scene and copy into texture
4884                 // (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)
4885                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4886                 {
4887                         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);
4888                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4889                                 goto error;
4890                         r_refdef.view = myview;
4891                         if(r_water_scissormode.integer)
4892                         {
4893                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4894                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4895                                 {
4896                                         p->rt_reflection = NULL;
4897                                         p->rt_refraction = NULL;
4898                                         p->rt_camera = NULL;
4899                                         continue;
4900                                 }
4901                         }
4902
4903                         // combined pvs (based on what can be seen from each surface center)
4904                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4905                         {
4906                                 r_refdef.view.usecustompvs = true;
4907                                 if (p->pvsvalid)
4908                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4909                                 else
4910                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4911                         }
4912
4913                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4914
4915                         r_refdef.view.clipplane = p->plane;
4916                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4917                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4918
4919                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4920                         {
4921                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4922                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4923                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4924                                 R_RenderView_UpdateViewVectors();
4925                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4926                                 {
4927                                         r_refdef.view.usecustompvs = true;
4928                                         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);
4929                                 }
4930                         }
4931
4932                         PlaneClassify(&r_refdef.view.clipplane);
4933
4934                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4935                         GL_ScissorTest(false);
4936                         R_ClearScreen(r_refdef.fogenabled);
4937                         GL_ScissorTest(true);
4938                         if(r_water_scissormode.integer & 2)
4939                                 R_View_UpdateWithScissor(myscissor);
4940                         else
4941                                 R_View_Update();
4942                         R_AnimCache_CacheVisibleEntities();
4943                         if(r_water_scissormode.integer & 1)
4944                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4945                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4946
4947                         r_fb.water.hideplayer = false;
4948                         p->rt_refraction = rt;
4949                 }
4950                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4951                 {
4952                         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);
4953                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4954                                 goto error;
4955                         r_refdef.view = myview;
4956
4957                         r_refdef.view.clipplane = p->plane;
4958                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4959                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4960
4961                         r_refdef.view.width = r_fb.water.camerawidth;
4962                         r_refdef.view.height = r_fb.water.cameraheight;
4963                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4964                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4965                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4966                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4967
4968                         if(p->camera_entity)
4969                         {
4970                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4971                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4972                         }
4973
4974                         // note: all of the view is used for displaying... so
4975                         // there is no use in scissoring
4976
4977                         // reverse the cullface settings for this render
4978                         r_refdef.view.cullface_front = GL_FRONT;
4979                         r_refdef.view.cullface_back = GL_BACK;
4980                         // also reverse the view matrix
4981                         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
4982                         R_RenderView_UpdateViewVectors();
4983                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4984                         {
4985                                 r_refdef.view.usecustompvs = true;
4986                                 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);
4987                         }
4988
4989                         // camera needs no clipplane
4990                         r_refdef.view.useclipplane = false;
4991                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4992                         r_refdef.view.usevieworiginculling = false;
4993
4994                         PlaneClassify(&r_refdef.view.clipplane);
4995
4996                         r_fb.water.hideplayer = false;
4997
4998                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4999                         GL_ScissorTest(false);
5000                         R_ClearScreen(r_refdef.fogenabled);
5001                         GL_ScissorTest(true);
5002                         R_View_Update();
5003                         R_AnimCache_CacheVisibleEntities();
5004                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5005
5006                         r_fb.water.hideplayer = false;
5007                         p->rt_camera = rt;
5008                 }
5009
5010         }
5011         r_fb.water.renderingscene = false;
5012         r_refdef.view = originalview;
5013         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5014         R_View_Update();
5015         R_AnimCache_CacheVisibleEntities();
5016         goto finish;
5017 error:
5018         r_refdef.view = originalview;
5019         r_fb.water.renderingscene = false;
5020         Cvar_SetValueQuick(&r_water, 0);
5021         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5022 finish:
5023         // lowquality hack, restore cvars
5024         if (qualityreduction > 0)
5025         {
5026                 if (qualityreduction >= 1)
5027                 {
5028                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5029                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5030                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5031                 }
5032                 if (qualityreduction >= 2)
5033                 {
5034                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5035                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5036                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5037                 }
5038         }
5039 }
5040
5041 static void R_Bloom_StartFrame(void)
5042 {
5043         int screentexturewidth, screentextureheight;
5044         textype_t textype = TEXTYPE_COLORBUFFER;
5045         double scale;
5046
5047         // clear the pointers to rendertargets from last frame as they're stale
5048         r_fb.rt_screen = NULL;
5049         r_fb.rt_bloom = NULL;
5050
5051         switch (vid.renderpath)
5052         {
5053         case RENDERPATH_GL32:
5054                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5055                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5056                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5057                 break;
5058         case RENDERPATH_GLES2:
5059                 r_fb.usedepthtextures = false;
5060                 break;
5061         }
5062
5063         if (r_viewscale_fpsscaling.integer)
5064         {
5065                 double actualframetime;
5066                 double targetframetime;
5067                 double adjust;
5068                 actualframetime = r_refdef.lastdrawscreentime;
5069                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5070                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5071                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5072                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5073                 {
5074                         if (adjust > 0)
5075                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5076                         else
5077                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5078                 }
5079                 viewscalefpsadjusted += adjust;
5080                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5081         }
5082         else
5083                 viewscalefpsadjusted = 1.0f;
5084
5085         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5086         if (vid.samples)
5087                 scale *= sqrt(vid.samples); // supersampling
5088         scale = bound(0.03125f, scale, 4.0f);
5089         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5090         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5091         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5092         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5093
5094         // set bloomwidth and bloomheight to the bloom resolution that will be
5095         // used (often less than the screen resolution for faster rendering)
5096         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5097         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5098         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5099         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5100         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5101
5102         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))
5103         {
5104                 Cvar_SetValueQuick(&r_bloom, 0);
5105                 Cvar_SetValueQuick(&r_motionblur, 0);
5106                 Cvar_SetValueQuick(&r_damageblur, 0);
5107         }
5108         if (!r_bloom.integer)
5109                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5110
5111         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5112         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5113         {
5114                 if (r_fb.ghosttexture)
5115                         R_FreeTexture(r_fb.ghosttexture);
5116                 r_fb.ghosttexture = NULL;
5117
5118                 r_fb.screentexturewidth = screentexturewidth;
5119                 r_fb.screentextureheight = screentextureheight;
5120                 r_fb.textype = textype;
5121
5122                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5123                 {
5124                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5125                                 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);
5126                         r_fb.ghosttexture_valid = false;
5127                 }
5128         }
5129
5130         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5131
5132         r_refdef.view.clear = true;
5133 }
5134
5135 static void R_Bloom_MakeTexture(void)
5136 {
5137         int x, range, dir;
5138         float xoffset, yoffset, r, brighten;
5139         float colorscale = r_bloom_colorscale.value;
5140         r_viewport_t bloomviewport;
5141         r_rendertarget_t *prev, *cur;
5142         textype_t textype = r_fb.rt_screen->colortextype[0];
5143
5144         r_refdef.stats[r_stat_bloom]++;
5145
5146         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5147
5148         // scale down screen texture to the bloom texture size
5149         CHECKGLERROR
5150         prev = r_fb.rt_screen;
5151         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5152         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5153         R_SetViewport(&bloomviewport);
5154         GL_CullFace(GL_NONE);
5155         GL_DepthTest(false);
5156         GL_BlendFunc(GL_ONE, GL_ZERO);
5157         GL_Color(colorscale, colorscale, colorscale, 1);
5158         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5159         // TODO: do boxfilter scale-down in shader?
5160         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5161         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5162         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5163         // we now have a properly scaled bloom image
5164
5165         // multiply bloom image by itself as many times as desired to darken it
5166         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5167         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5168         {
5169                 prev = cur;
5170                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5171                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5172                 x *= 2;
5173                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5174                 if(x <= 2)
5175                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5176                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5177                 GL_Color(1,1,1,1); // no fix factor supported here
5178                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5179                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5180                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5181                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5182         }
5183         CHECKGLERROR
5184
5185         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5186         brighten = r_bloom_brighten.value;
5187         brighten = sqrt(brighten);
5188         if(range >= 1)
5189                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5190
5191         for (dir = 0;dir < 2;dir++)
5192         {
5193                 prev = cur;
5194                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5195                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5196                 // blend on at multiple vertical offsets to achieve a vertical blur
5197                 // TODO: do offset blends using GLSL
5198                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5199                 CHECKGLERROR
5200                 GL_BlendFunc(GL_ONE, GL_ZERO);
5201                 CHECKGLERROR
5202                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5203                 CHECKGLERROR
5204                 for (x = -range;x <= range;x++)
5205                 {
5206                         if (!dir){xoffset = 0;yoffset = x;}
5207                         else {xoffset = x;yoffset = 0;}
5208                         xoffset /= (float)prev->texturewidth;
5209                         yoffset /= (float)prev->textureheight;
5210                         // compute a texcoord array with the specified x and y offset
5211                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5212                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5213                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5214                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5215                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5216                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5217                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5218                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5219                         // this r value looks like a 'dot' particle, fading sharply to
5220                         // black at the edges
5221                         // (probably not realistic but looks good enough)
5222                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5223                         //r = brighten/(range*2+1);
5224                         r = brighten / (range * 2 + 1);
5225                         if(range >= 1)
5226                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5227                         if (r <= 0)
5228                                 continue;
5229                         CHECKGLERROR
5230                         GL_Color(r, r, r, 1);
5231                         CHECKGLERROR
5232                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5233                         CHECKGLERROR
5234                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5235                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5236                         CHECKGLERROR
5237                         GL_BlendFunc(GL_ONE, GL_ONE);
5238                         CHECKGLERROR
5239                 }
5240         }
5241
5242         // now we have the bloom image, so keep track of it
5243         r_fb.rt_bloom = cur;
5244 }
5245
5246 static qbool R_BlendView_IsTrivial(int viewwidth, int viewheight, int width, int height)
5247 {
5248         // Scaling requested?
5249         if (viewwidth != width || viewheight != height)
5250                 return false;
5251         // Higher bit depth or explicit FBO requested?
5252         if (r_viewfbo.integer)
5253                 return false;
5254         // Non-trivial postprocessing shader permutation?
5255         if (r_fb.bloomwidth
5256         || r_refdef.viewblend[3] > 0
5257         || !vid_gammatables_trivial
5258         || r_glsl_postprocess.integer
5259         || ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1)))
5260                 return false;
5261         // Other reasons for a non-trivial default postprocessing shader?
5262         // (See R_CompileShader_CheckStaticParms but only those relevant for MODE_POSTPROCESS in shader_glsl.h)
5263         // Skip: if (r_glsl_saturation_redcompensate.integer) (already covered by saturation above).
5264         // Skip: if (r_glsl_postprocess.integer) (already covered by r_glsl_postprocess above).
5265         // Skip: if (r_glsl_postprocess_uservec1_enable.integer) (already covered by r_glsl_postprocessing above).
5266         if (r_fxaa.integer)
5267                 return false;
5268         if (r_colorfringe.value)
5269                 return false;
5270         return true;
5271 }
5272
5273 static void R_MotionBlurView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5274 {
5275         R_EntityMatrix(&identitymatrix);
5276
5277         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || (r_damageblur.value > 0 && cl.cshifts[CSHIFT_DAMAGE].percent != 0)) && r_fb.ghosttexture)
5278         {
5279                 // declare variables
5280                 float blur_factor, blur_mouseaccel, blur_velocity;
5281                 static float blur_average;
5282                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5283
5284                 // set a goal for the factoring
5285                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5286                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5287                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5288                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5289                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5290                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5291
5292                 // from the goal, pick an averaged value between goal and last value
5293                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5294                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5295
5296                 // enforce minimum amount of blur
5297                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5298
5299                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5300
5301                 // calculate values into a standard alpha
5302                 cl.motionbluralpha = 1 - exp(-
5303                                 (
5304                                         (r_motionblur.value * blur_factor / 80)
5305                                         +
5306                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5307                                 )
5308                                 /
5309                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5310                                 );
5311
5312                 // randomization for the blur value to combat persistent ghosting
5313                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5314                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5315
5316                 // apply the blur on top of the current view
5317                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5318                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5319                 {
5320                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5321                         GL_Color(1, 1, 1, cl.motionbluralpha);
5322                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5323                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5324                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5325                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5326                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5327                 }
5328
5329                 // updates old view angles for next pass
5330                 VectorCopy(cl.viewangles, blur_oldangles);
5331
5332                 // copy view into the ghost texture
5333                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5334                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5335                 r_fb.ghosttexture_valid = true;
5336         }
5337 }
5338
5339 static void R_BlendView(rtexture_t *viewcolortexture, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5340 {
5341         uint64_t permutation;
5342         float uservecs[4][4];
5343         rtexture_t *viewtexture;
5344         rtexture_t *bloomtexture;
5345
5346         R_EntityMatrix(&identitymatrix);
5347
5348         if (r_fb.bloomwidth)
5349         {
5350                 // make the bloom texture
5351                 R_Bloom_MakeTexture();
5352         }
5353
5354 #if _MSC_VER >= 1400
5355 #define sscanf sscanf_s
5356 #endif
5357         memset(uservecs, 0, sizeof(uservecs));
5358         if (r_glsl_postprocess_uservec1_enable.integer)
5359                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5360         if (r_glsl_postprocess_uservec2_enable.integer)
5361                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5362         if (r_glsl_postprocess_uservec3_enable.integer)
5363                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5364         if (r_glsl_postprocess_uservec4_enable.integer)
5365                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5366
5367         // render to the screen fbo
5368         R_ResetViewRendering2D(fbo, depthtexture, colortexture, x, y, width, height);
5369         GL_Color(1, 1, 1, 1);
5370         GL_BlendFunc(GL_ONE, GL_ZERO);
5371
5372         viewtexture = viewcolortexture;
5373         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5374
5375         if (r_rendertarget_debug.integer >= 0)
5376         {
5377                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5378                 if (rt && rt->colortexture[0])
5379                 {
5380                         viewtexture = rt->colortexture[0];
5381                         bloomtexture = NULL;
5382                 }
5383         }
5384
5385         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5386         switch(vid.renderpath)
5387         {
5388         case RENDERPATH_GL32:
5389         case RENDERPATH_GLES2:
5390                 permutation =
5391                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5392                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5393                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5394                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5395                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5396                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5397                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5398                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5399                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5400                 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]);
5401                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5402                 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]);
5403                 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]);
5404                 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]);
5405                 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]);
5406                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5407                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5408                 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);
5409                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5410                 break;
5411         }
5412         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5413         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5414 }
5415
5416 matrix4x4_t r_waterscrollmatrix;
5417
5418 void R_UpdateFog(void)
5419 {
5420         // Nehahra fog
5421         if (gamemode == GAME_NEHAHRA)
5422         {
5423                 if (gl_fogenable.integer)
5424                 {
5425                         r_refdef.oldgl_fogenable = true;
5426                         r_refdef.fog_density = gl_fogdensity.value;
5427                         r_refdef.fog_red = gl_fogred.value;
5428                         r_refdef.fog_green = gl_foggreen.value;
5429                         r_refdef.fog_blue = gl_fogblue.value;
5430                         r_refdef.fog_alpha = 1;
5431                         r_refdef.fog_start = 0;
5432                         r_refdef.fog_end = gl_skyclip.value;
5433                         r_refdef.fog_height = 1<<30;
5434                         r_refdef.fog_fadedepth = 128;
5435                 }
5436                 else if (r_refdef.oldgl_fogenable)
5437                 {
5438                         r_refdef.oldgl_fogenable = false;
5439                         r_refdef.fog_density = 0;
5440                         r_refdef.fog_red = 0;
5441                         r_refdef.fog_green = 0;
5442                         r_refdef.fog_blue = 0;
5443                         r_refdef.fog_alpha = 0;
5444                         r_refdef.fog_start = 0;
5445                         r_refdef.fog_end = 0;
5446                         r_refdef.fog_height = 1<<30;
5447                         r_refdef.fog_fadedepth = 128;
5448                 }
5449         }
5450
5451         // fog parms
5452         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5453         r_refdef.fog_start = max(0, r_refdef.fog_start);
5454         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5455
5456         if (r_refdef.fog_density && r_drawfog.integer)
5457         {
5458                 r_refdef.fogenabled = true;
5459                 // this is the point where the fog reaches 0.9986 alpha, which we
5460                 // consider a good enough cutoff point for the texture
5461                 // (0.9986 * 256 == 255.6)
5462                 if (r_fog_exp2.integer)
5463                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5464                 else
5465                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5466                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5467                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5468                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5469                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5470                         R_BuildFogHeightTexture();
5471                 // fog color was already set
5472                 // update the fog texture
5473                 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)
5474                         R_BuildFogTexture();
5475                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5476                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5477         }
5478         else
5479                 r_refdef.fogenabled = false;
5480
5481         // fog color
5482         if (r_refdef.fog_density)
5483         {
5484                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5485                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5486                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5487
5488                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5489                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5490                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5491                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5492
5493                 {
5494                         vec3_t fogvec;
5495                         VectorCopy(r_refdef.fogcolor, fogvec);
5496                         //   color.rgb *= ContrastBoost * SceneBrightness;
5497                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5498                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5499                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5500                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5501                 }
5502         }
5503 }
5504
5505 void R_UpdateVariables(void)
5506 {
5507         R_Textures_Frame();
5508
5509         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5510
5511         r_refdef.farclip = r_farclip_base.value;
5512         if (r_refdef.scene.worldmodel)
5513                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5514         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5515
5516         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5517                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5518         r_refdef.polygonfactor = 0;
5519         r_refdef.polygonoffset = 0;
5520
5521         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5522         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5523         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5524         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5525         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5526         if (r_refdef.scene.worldmodel)
5527         {
5528                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5529
5530                 // Apply the default lightstyle to the lightmap even on q3bsp
5531                 if (cl.worldmodel && cl.worldmodel->type == mod_brushq3) {
5532                         r_refdef.scene.lightmapintensity *= r_refdef.scene.rtlightstylevalue[0];
5533                 }
5534         }
5535         if (r_showsurfaces.integer)
5536         {
5537                 r_refdef.scene.rtworld = false;
5538                 r_refdef.scene.rtworldshadows = false;
5539                 r_refdef.scene.rtdlight = false;
5540                 r_refdef.scene.rtdlightshadows = false;
5541                 r_refdef.scene.lightmapintensity = 0;
5542         }
5543
5544         r_gpuskeletal = false;
5545         switch(vid.renderpath)
5546         {
5547         case RENDERPATH_GL32:
5548                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5549         case RENDERPATH_GLES2:
5550                 if(!vid_gammatables_trivial)
5551                 {
5552                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5553                         {
5554                                 // build GLSL gamma texture
5555 #define RAMPWIDTH 256
5556                                 unsigned short ramp[RAMPWIDTH * 3];
5557                                 unsigned char rampbgr[RAMPWIDTH][4];
5558                                 int i;
5559
5560                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5561
5562                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5563                                 for(i = 0; i < RAMPWIDTH; ++i)
5564                                 {
5565                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5566                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5567                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5568                                         rampbgr[i][3] = 0;
5569                                 }
5570                                 if (r_texture_gammaramps)
5571                                 {
5572                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5573                                 }
5574                                 else
5575                                 {
5576                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5577                                 }
5578                         }
5579                 }
5580                 else
5581                 {
5582                         // remove GLSL gamma texture
5583                 }
5584                 break;
5585         }
5586 }
5587
5588 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5589 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5590 /*
5591 ================
5592 R_SelectScene
5593 ================
5594 */
5595 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5596         if( scenetype != r_currentscenetype ) {
5597                 // store the old scenetype
5598                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5599                 r_currentscenetype = scenetype;
5600                 // move in the new scene
5601                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5602         }
5603 }
5604
5605 /*
5606 ================
5607 R_GetScenePointer
5608 ================
5609 */
5610 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5611 {
5612         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5613         if( scenetype == r_currentscenetype ) {
5614                 return &r_refdef.scene;
5615         } else {
5616                 return &r_scenes_store[ scenetype ];
5617         }
5618 }
5619
5620 static int R_SortEntities_Compare(const void *ap, const void *bp)
5621 {
5622         const entity_render_t *a = *(const entity_render_t **)ap;
5623         const entity_render_t *b = *(const entity_render_t **)bp;
5624
5625         // 1. compare model
5626         if(a->model < b->model)
5627                 return -1;
5628         if(a->model > b->model)
5629                 return +1;
5630
5631         // 2. compare skin
5632         // TODO possibly calculate the REAL skinnum here first using
5633         // skinscenes?
5634         if(a->skinnum < b->skinnum)
5635                 return -1;
5636         if(a->skinnum > b->skinnum)
5637                 return +1;
5638
5639         // everything we compared is equal
5640         return 0;
5641 }
5642 static void R_SortEntities(void)
5643 {
5644         // below or equal 2 ents, sorting never gains anything
5645         if(r_refdef.scene.numentities <= 2)
5646                 return;
5647         // sort
5648         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5649 }
5650
5651 /*
5652 ================
5653 R_RenderView
5654 ================
5655 */
5656 extern cvar_t r_shadow_bouncegrid;
5657 extern cvar_t v_isometric;
5658 extern void V_MakeViewIsometric(void);
5659 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5660 {
5661         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5662         int viewfbo = 0;
5663         rtexture_t *viewdepthtexture = NULL;
5664         rtexture_t *viewcolortexture = NULL;
5665         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5666         qbool skipblend;
5667
5668         // finish any 2D rendering that was queued
5669         DrawQ_Finish();
5670
5671         if (r_timereport_active)
5672                 R_TimeReport("start");
5673         r_textureframe++; // used only by R_GetCurrentTexture
5674         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5675
5676         if(R_CompileShader_CheckStaticParms())
5677                 R_GLSL_Restart_f(cmd_local);
5678
5679         if (!r_drawentities.integer)
5680                 r_refdef.scene.numentities = 0;
5681         else if (r_sortentities.integer)
5682                 R_SortEntities();
5683
5684         R_AnimCache_ClearCache();
5685
5686         /* adjust for stereo display */
5687         if(R_Stereo_Active())
5688         {
5689                 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);
5690                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5691         }
5692
5693         if (r_refdef.view.isoverlay)
5694         {
5695                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5696                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5697                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5698                 R_TimeReport("depthclear");
5699
5700                 r_refdef.view.showdebug = false;
5701
5702                 r_fb.water.enabled = false;
5703                 r_fb.water.numwaterplanes = 0;
5704
5705                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5706
5707                 r_refdef.view.matrix = originalmatrix;
5708
5709                 CHECKGLERROR
5710                 return;
5711         }
5712
5713         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5714         {
5715                 r_refdef.view.matrix = originalmatrix;
5716                 return;
5717         }
5718
5719         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5720         if (v_isometric.integer && r_refdef.view.ismain)
5721                 V_MakeViewIsometric();
5722
5723         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5724
5725         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5726                 // in sRGB fallback, behave similar to true sRGB: convert this
5727                 // value from linear to sRGB
5728                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5729
5730         R_RenderView_UpdateViewVectors();
5731
5732         R_Shadow_UpdateWorldLightSelection();
5733
5734         // this will set up r_fb.rt_screen
5735         R_Bloom_StartFrame();
5736
5737         // apply bloom brightness offset
5738         if(r_fb.rt_bloom)
5739                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5740
5741         skipblend = R_BlendView_IsTrivial(r_fb.rt_screen->texturewidth, r_fb.rt_screen->textureheight, width, height);
5742         if (skipblend)
5743         {
5744                 // Render to the screen right away.
5745                 viewfbo = fbo;
5746                 viewdepthtexture = depthtexture;
5747                 viewcolortexture = colortexture;
5748                 viewx = x;
5749                 viewy = y;
5750                 viewwidth = width;
5751                 viewheight = height;
5752         }
5753         else if (r_fb.rt_screen)
5754         {
5755                 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5756                 viewfbo = r_fb.rt_screen->fbo;
5757                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5758                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5759                 viewx = 0;
5760                 viewy = 0;
5761                 viewwidth = r_fb.rt_screen->texturewidth;
5762                 viewheight = r_fb.rt_screen->textureheight;
5763         }
5764
5765         R_Water_StartFrame(viewwidth, viewheight);
5766
5767         CHECKGLERROR
5768         if (r_timereport_active)
5769                 R_TimeReport("viewsetup");
5770
5771         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5772
5773         // clear the whole fbo every frame - otherwise the driver will consider
5774         // it to be an inter-frame texture and stall in multi-gpu configurations
5775         if (r_fb.rt_screen)
5776                 GL_ScissorTest(false);
5777         R_ClearScreen(r_refdef.fogenabled);
5778         if (r_timereport_active)
5779                 R_TimeReport("viewclear");
5780
5781         r_refdef.view.clear = true;
5782
5783         r_refdef.view.showdebug = true;
5784
5785         R_View_Update();
5786         if (r_timereport_active)
5787                 R_TimeReport("visibility");
5788
5789         R_AnimCache_CacheVisibleEntities();
5790         if (r_timereport_active)
5791                 R_TimeReport("animcache");
5792
5793         R_Shadow_UpdateBounceGridTexture();
5794         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5795
5796         r_fb.water.numwaterplanes = 0;
5797         if (r_fb.water.enabled)
5798                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5799
5800         // for the actual view render we use scissoring a fair amount, so scissor
5801         // test needs to be on
5802         if (r_fb.rt_screen)
5803                 GL_ScissorTest(true);
5804         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5805         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5806         r_fb.water.numwaterplanes = 0;
5807
5808         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5809         GL_ScissorTest(false);
5810
5811         R_MotionBlurView(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5812         if (!skipblend)
5813                 R_BlendView(viewcolortexture, fbo, depthtexture, colortexture, x, y, width, height);
5814         if (r_timereport_active)
5815                 R_TimeReport("blendview");
5816
5817         r_refdef.view.matrix = originalmatrix;
5818
5819         CHECKGLERROR
5820
5821         // go back to 2d rendering
5822         DrawQ_Start();
5823 }
5824
5825 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5826 {
5827         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5828         {
5829                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5830                 if (r_timereport_active)
5831                         R_TimeReport("waterworld");
5832         }
5833
5834         // don't let sound skip if going slow
5835         if (r_refdef.scene.extraupdate)
5836                 S_ExtraUpdate ();
5837
5838         R_DrawModelsAddWaterPlanes();
5839         if (r_timereport_active)
5840                 R_TimeReport("watermodels");
5841
5842         if (r_fb.water.numwaterplanes)
5843         {
5844                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5845                 if (r_timereport_active)
5846                         R_TimeReport("waterscenes");
5847         }
5848 }
5849
5850 extern cvar_t cl_locs_show;
5851 static void R_DrawLocs(void);
5852 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5853 static void R_DrawModelDecals(void);
5854 extern qbool r_shadow_usingdeferredprepass;
5855 extern int r_shadow_shadowmapatlas_modelshadows_size;
5856 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5857 {
5858         qbool shadowmapping = false;
5859
5860         if (r_timereport_active)
5861                 R_TimeReport("beginscene");
5862
5863         r_refdef.stats[r_stat_renders]++;
5864
5865         R_UpdateFog();
5866
5867         // don't let sound skip if going slow
5868         if (r_refdef.scene.extraupdate)
5869                 S_ExtraUpdate ();
5870
5871         R_MeshQueue_BeginScene();
5872
5873         R_SkyStartFrame();
5874
5875         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);
5876
5877         if (r_timereport_active)
5878                 R_TimeReport("skystartframe");
5879
5880         if (cl.csqc_vidvars.drawworld)
5881         {
5882                 // don't let sound skip if going slow
5883                 if (r_refdef.scene.extraupdate)
5884                         S_ExtraUpdate ();
5885
5886                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5887                 {
5888                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5889                         if (r_timereport_active)
5890                                 R_TimeReport("worldsky");
5891                 }
5892
5893                 if (R_DrawBrushModelsSky() && r_timereport_active)
5894                         R_TimeReport("bmodelsky");
5895
5896                 if (skyrendermasked && skyrenderlater)
5897                 {
5898                         // we have to force off the water clipping plane while rendering sky
5899                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5900                         R_Sky();
5901                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5902                         if (r_timereport_active)
5903                                 R_TimeReport("sky");
5904                 }
5905         }
5906
5907         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5908         r_shadow_viewfbo = viewfbo;
5909         r_shadow_viewdepthtexture = viewdepthtexture;
5910         r_shadow_viewcolortexture = viewcolortexture;
5911         r_shadow_viewx = viewx;
5912         r_shadow_viewy = viewy;
5913         r_shadow_viewwidth = viewwidth;
5914         r_shadow_viewheight = viewheight;
5915
5916         R_Shadow_PrepareModelShadows();
5917         R_Shadow_PrepareLights();
5918         if (r_timereport_active)
5919                 R_TimeReport("preparelights");
5920
5921         // render all the shadowmaps that will be used for this view
5922         shadowmapping = R_Shadow_ShadowMappingEnabled();
5923         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5924         {
5925                 R_Shadow_DrawShadowMaps();
5926                 if (r_timereport_active)
5927                         R_TimeReport("shadowmaps");
5928         }
5929
5930         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5931         if (r_shadow_usingdeferredprepass)
5932                 R_Shadow_DrawPrepass();
5933
5934         // now we begin the forward pass of the view render
5935         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5936         {
5937                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5938                 if (r_timereport_active)
5939                         R_TimeReport("worlddepth");
5940         }
5941         if (r_depthfirst.integer >= 2)
5942         {
5943                 R_DrawModelsDepth();
5944                 if (r_timereport_active)
5945                         R_TimeReport("modeldepth");
5946         }
5947
5948         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5949         {
5950                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5951                 if (r_timereport_active)
5952                         R_TimeReport("world");
5953         }
5954
5955         // don't let sound skip if going slow
5956         if (r_refdef.scene.extraupdate)
5957                 S_ExtraUpdate ();
5958
5959         R_DrawModels();
5960         if (r_timereport_active)
5961                 R_TimeReport("models");
5962
5963         // don't let sound skip if going slow
5964         if (r_refdef.scene.extraupdate)
5965                 S_ExtraUpdate ();
5966
5967         if (!r_shadow_usingdeferredprepass)
5968         {
5969                 R_Shadow_DrawLights();
5970                 if (r_timereport_active)
5971                         R_TimeReport("rtlights");
5972         }
5973
5974         // don't let sound skip if going slow
5975         if (r_refdef.scene.extraupdate)
5976                 S_ExtraUpdate ();
5977
5978         if (cl.csqc_vidvars.drawworld)
5979         {
5980                 R_DrawModelDecals();
5981                 if (r_timereport_active)
5982                         R_TimeReport("modeldecals");
5983
5984                 R_DrawParticles();
5985                 if (r_timereport_active)
5986                         R_TimeReport("particles");
5987
5988                 R_DrawExplosions();
5989                 if (r_timereport_active)
5990                         R_TimeReport("explosions");
5991         }
5992
5993         if (r_refdef.view.showdebug)
5994         {
5995                 if (cl_locs_show.integer)
5996                 {
5997                         R_DrawLocs();
5998                         if (r_timereport_active)
5999                                 R_TimeReport("showlocs");
6000                 }
6001
6002                 if (r_drawportals.integer)
6003                 {
6004                         R_DrawPortals();
6005                         if (r_timereport_active)
6006                                 R_TimeReport("portals");
6007                 }
6008
6009                 if (r_showbboxes_client.value > 0)
6010                 {
6011                         R_DrawEntityBBoxes(CLVM_prog);
6012                         if (r_timereport_active)
6013                                 R_TimeReport("clbboxes");
6014                 }
6015                 if (r_showbboxes.value > 0)
6016                 {
6017                         R_DrawEntityBBoxes(SVVM_prog);
6018                         if (r_timereport_active)
6019                                 R_TimeReport("svbboxes");
6020                 }
6021         }
6022
6023         if (r_transparent.integer)
6024         {
6025                 R_MeshQueue_RenderTransparent();
6026                 if (r_timereport_active)
6027                         R_TimeReport("drawtrans");
6028         }
6029
6030         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))
6031         {
6032                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6033                 if (r_timereport_active)
6034                         R_TimeReport("worlddebug");
6035                 R_DrawModelsDebug();
6036                 if (r_timereport_active)
6037                         R_TimeReport("modeldebug");
6038         }
6039
6040         if (cl.csqc_vidvars.drawworld)
6041         {
6042                 R_Shadow_DrawCoronas();
6043                 if (r_timereport_active)
6044                         R_TimeReport("coronas");
6045         }
6046
6047         // don't let sound skip if going slow
6048         if (r_refdef.scene.extraupdate)
6049                 S_ExtraUpdate ();
6050 }
6051
6052 static const unsigned short bboxelements[36] =
6053 {
6054         5, 1, 3, 5, 3, 7,
6055         6, 2, 0, 6, 0, 4,
6056         7, 3, 2, 7, 2, 6,
6057         4, 0, 1, 4, 1, 5,
6058         4, 5, 7, 4, 7, 6,
6059         1, 0, 2, 1, 2, 3,
6060 };
6061
6062 #define BBOXEDGES 13
6063 static const float bboxedges[BBOXEDGES][6] =
6064 {
6065         // whole box
6066         { 0, 0, 0, 1, 1, 1 },
6067         // bottom edges
6068         { 0, 0, 0, 0, 1, 0 },
6069         { 0, 0, 0, 1, 0, 0 },
6070         { 0, 1, 0, 1, 1, 0 },
6071         { 1, 0, 0, 1, 1, 0 },
6072         // top edges
6073         { 0, 0, 1, 0, 1, 1 },
6074         { 0, 0, 1, 1, 0, 1 },
6075         { 0, 1, 1, 1, 1, 1 },
6076         { 1, 0, 1, 1, 1, 1 },
6077         // vertical edges
6078         { 0, 0, 0, 0, 0, 1 },
6079         { 1, 0, 0, 1, 0, 1 },
6080         { 0, 1, 0, 0, 1, 1 },
6081         { 1, 1, 0, 1, 1, 1 },
6082 };
6083
6084 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6085 {
6086         int numvertices = BBOXEDGES * 8;
6087         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6088         int numtriangles = BBOXEDGES * 12;
6089         unsigned short elements[BBOXEDGES * 36];
6090         int i, edge;
6091         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6092
6093         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6094
6095         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6096         GL_DepthMask(false);
6097         GL_DepthRange(0, 1);
6098         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6099
6100         for (edge = 0; edge < BBOXEDGES; edge++)
6101         {
6102                 for (i = 0; i < 3; i++)
6103                 {
6104                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6105                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6106                 }
6107                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6108                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6109                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6110                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6111                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6112                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6113                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6114                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6115                 for (i = 0; i < 36; i++)
6116                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6117         }
6118         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6119         if (r_refdef.fogenabled)
6120         {
6121                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6122                 {
6123                         f1 = RSurf_FogVertex(v);
6124                         f2 = 1 - f1;
6125                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6126                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6127                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6128                 }
6129         }
6130         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6131         R_Mesh_ResetTextureState();
6132         R_SetupShader_Generic_NoTexture(false, false);
6133         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6134 }
6135
6136 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6137 {
6138         // hacky overloading of the parameters
6139         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6140         int i;
6141         float color[4];
6142         prvm_edict_t *edict;
6143
6144         GL_CullFace(GL_NONE);
6145         R_SetupShader_Generic_NoTexture(false, false);
6146
6147         for (i = 0;i < numsurfaces;i++)
6148         {
6149                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6150                 switch ((int)PRVM_serveredictfloat(edict, solid))
6151                 {
6152                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6153                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6154                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6155                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6156                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6157                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6158                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6159                 }
6160                 if (prog == CLVM_prog)
6161                         color[3] *= r_showbboxes_client.value;
6162                 else
6163                         color[3] *= r_showbboxes.value;
6164                 color[3] = bound(0, color[3], 1);
6165                 GL_DepthTest(!r_showdisabledepthtest.integer);
6166                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6167         }
6168 }
6169
6170 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6171 {
6172         int i;
6173         prvm_edict_t *edict;
6174         vec3_t center;
6175
6176         if (prog == NULL)
6177                 return;
6178
6179         for (i = 0; i < prog->num_edicts; i++)
6180         {
6181                 edict = PRVM_EDICT_NUM(i);
6182                 if (edict->free)
6183                         continue;
6184                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6185                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6186                         continue;
6187                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6188                         continue;
6189                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6190                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6191         }
6192 }
6193
6194 static const int nomodelelement3i[24] =
6195 {
6196         5, 2, 0,
6197         5, 1, 2,
6198         5, 0, 3,
6199         5, 3, 1,
6200         0, 2, 4,
6201         2, 1, 4,
6202         3, 0, 4,
6203         1, 3, 4
6204 };
6205
6206 static const unsigned short nomodelelement3s[24] =
6207 {
6208         5, 2, 0,
6209         5, 1, 2,
6210         5, 0, 3,
6211         5, 3, 1,
6212         0, 2, 4,
6213         2, 1, 4,
6214         3, 0, 4,
6215         1, 3, 4
6216 };
6217
6218 static const float nomodelvertex3f[6*3] =
6219 {
6220         -16,   0,   0,
6221          16,   0,   0,
6222           0, -16,   0,
6223           0,  16,   0,
6224           0,   0, -16,
6225           0,   0,  16
6226 };
6227
6228 static const float nomodelcolor4f[6*4] =
6229 {
6230         0.0f, 0.0f, 0.5f, 1.0f,
6231         0.0f, 0.0f, 0.5f, 1.0f,
6232         0.0f, 0.5f, 0.0f, 1.0f,
6233         0.0f, 0.5f, 0.0f, 1.0f,
6234         0.5f, 0.0f, 0.0f, 1.0f,
6235         0.5f, 0.0f, 0.0f, 1.0f
6236 };
6237
6238 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6239 {
6240         int i;
6241         float f1, f2, *c;
6242         float color4f[6*4];
6243
6244         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);
6245
6246         // this is only called once per entity so numsurfaces is always 1, and
6247         // surfacelist is always {0}, so this code does not handle batches
6248
6249         if (rsurface.ent_flags & RENDER_ADDITIVE)
6250         {
6251                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6252                 GL_DepthMask(false);
6253         }
6254         else if (ent->alpha < 1)
6255         {
6256                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6257                 GL_DepthMask(false);
6258         }
6259         else
6260         {
6261                 GL_BlendFunc(GL_ONE, GL_ZERO);
6262                 GL_DepthMask(true);
6263         }
6264         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6265         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6266         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6267         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6268         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6269         for (i = 0, c = color4f;i < 6;i++, c += 4)
6270         {
6271                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6272                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6273                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6274                 c[3] *= ent->alpha;
6275         }
6276         if (r_refdef.fogenabled)
6277         {
6278                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6279                 {
6280                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6281                         f2 = 1 - f1;
6282                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6283                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6284                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6285                 }
6286         }
6287 //      R_Mesh_ResetTextureState();
6288         R_SetupShader_Generic_NoTexture(false, false);
6289         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6290         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6291 }
6292
6293 void R_DrawNoModel(entity_render_t *ent)
6294 {
6295         vec3_t org;
6296         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6297         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6298                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6299         else
6300                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6301 }
6302
6303 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6304 {
6305         vec3_t right1, right2, diff, normal;
6306
6307         VectorSubtract (org2, org1, normal);
6308
6309         // calculate 'right' vector for start
6310         VectorSubtract (r_refdef.view.origin, org1, diff);
6311         CrossProduct (normal, diff, right1);
6312         VectorNormalize (right1);
6313
6314         // calculate 'right' vector for end
6315         VectorSubtract (r_refdef.view.origin, org2, diff);
6316         CrossProduct (normal, diff, right2);
6317         VectorNormalize (right2);
6318
6319         vert[ 0] = org1[0] + width * right1[0];
6320         vert[ 1] = org1[1] + width * right1[1];
6321         vert[ 2] = org1[2] + width * right1[2];
6322         vert[ 3] = org1[0] - width * right1[0];
6323         vert[ 4] = org1[1] - width * right1[1];
6324         vert[ 5] = org1[2] - width * right1[2];
6325         vert[ 6] = org2[0] - width * right2[0];
6326         vert[ 7] = org2[1] - width * right2[1];
6327         vert[ 8] = org2[2] - width * right2[2];
6328         vert[ 9] = org2[0] + width * right2[0];
6329         vert[10] = org2[1] + width * right2[1];
6330         vert[11] = org2[2] + width * right2[2];
6331 }
6332
6333 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)
6334 {
6335         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6336         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6337         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6338         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6339         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6340         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6341         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6342         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6343         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6344         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6345         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6346         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6347 }
6348
6349 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6350 {
6351         int i;
6352         float *vertex3f;
6353         float v[3];
6354         VectorSet(v, x, y, z);
6355         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6356                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6357                         break;
6358         if (i == mesh->numvertices)
6359         {
6360                 if (mesh->numvertices < mesh->maxvertices)
6361                 {
6362                         VectorCopy(v, vertex3f);
6363                         mesh->numvertices++;
6364                 }
6365                 return mesh->numvertices;
6366         }
6367         else
6368                 return i;
6369 }
6370
6371 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6372 {
6373         int i;
6374         int *e, element[3];
6375         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6376         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6377         e = mesh->element3i + mesh->numtriangles * 3;
6378         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6379         {
6380                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6381                 if (mesh->numtriangles < mesh->maxtriangles)
6382                 {
6383                         *e++ = element[0];
6384                         *e++ = element[1];
6385                         *e++ = element[2];
6386                         mesh->numtriangles++;
6387                 }
6388                 element[1] = element[2];
6389         }
6390 }
6391
6392 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6393 {
6394         int i;
6395         int *e, element[3];
6396         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6397         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6398         e = mesh->element3i + mesh->numtriangles * 3;
6399         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6400         {
6401                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6402                 if (mesh->numtriangles < mesh->maxtriangles)
6403                 {
6404                         *e++ = element[0];
6405                         *e++ = element[1];
6406                         *e++ = element[2];
6407                         mesh->numtriangles++;
6408                 }
6409                 element[1] = element[2];
6410         }
6411 }
6412
6413 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6414 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6415 {
6416         int planenum, planenum2;
6417         int w;
6418         int tempnumpoints;
6419         mplane_t *plane, *plane2;
6420         double maxdist;
6421         double temppoints[2][256*3];
6422         // figure out how large a bounding box we need to properly compute this brush
6423         maxdist = 0;
6424         for (w = 0;w < numplanes;w++)
6425                 maxdist = max(maxdist, fabs(planes[w].dist));
6426         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6427         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6428         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6429         {
6430                 w = 0;
6431                 tempnumpoints = 4;
6432                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6433                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6434                 {
6435                         if (planenum2 == planenum)
6436                                 continue;
6437                         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);
6438                         w = !w;
6439                 }
6440                 if (tempnumpoints < 3)
6441                         continue;
6442                 // generate elements forming a triangle fan for this polygon
6443                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6444         }
6445 }
6446
6447 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6448 {
6449         if(parms[0] == 0 && parms[1] == 0)
6450                 return false;
6451         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6452                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6453                         return false;
6454         return true;
6455 }
6456
6457 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6458 {
6459         double index, f;
6460         index = parms[2] + rsurface.shadertime * parms[3];
6461         index -= floor(index);
6462         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6463         {
6464         default:
6465         case Q3WAVEFUNC_NONE:
6466         case Q3WAVEFUNC_NOISE:
6467         case Q3WAVEFUNC_COUNT:
6468                 f = 0;
6469                 break;
6470         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6471         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6472         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6473         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6474         case Q3WAVEFUNC_TRIANGLE:
6475                 index *= 4;
6476                 f = index - floor(index);
6477                 if (index < 1)
6478                 {
6479                         // f = f;
6480                 }
6481                 else if (index < 2)
6482                         f = 1 - f;
6483                 else if (index < 3)
6484                         f = -f;
6485                 else
6486                         f = -(1 - f);
6487                 break;
6488         }
6489         f = parms[0] + parms[1] * f;
6490         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6491                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6492         return (float) f;
6493 }
6494
6495 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6496 {
6497         int w, h, idx;
6498         float shadertime;
6499         float f;
6500         float offsetd[2];
6501         float tcmat[12];
6502         matrix4x4_t matrix, temp;
6503         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6504         // it's better to have one huge fixup every 9 hours than gradual
6505         // degradation over time which looks consistently bad after many hours.
6506         //
6507         // tcmod scroll in particular suffers from this degradation which can't be
6508         // effectively worked around even with floor() tricks because we don't
6509         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6510         // a workaround involving floor() would be incorrect anyway...
6511         shadertime = rsurface.shadertime;
6512         if (shadertime >= 32768.0f)
6513                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6514         switch(tcmod->tcmod)
6515         {
6516                 case Q3TCMOD_COUNT:
6517                 case Q3TCMOD_NONE:
6518                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6519                                 matrix = r_waterscrollmatrix;
6520                         else
6521                                 matrix = identitymatrix;
6522                         break;
6523                 case Q3TCMOD_ENTITYTRANSLATE:
6524                         // this is used in Q3 to allow the gamecode to control texcoord
6525                         // scrolling on the entity, which is not supported in darkplaces yet.
6526                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6527                         break;
6528                 case Q3TCMOD_ROTATE:
6529                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6530                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6531                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6532                         break;
6533                 case Q3TCMOD_SCALE:
6534                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6535                         break;
6536                 case Q3TCMOD_SCROLL:
6537                         // this particular tcmod is a "bug for bug" compatible one with regards to
6538                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6539                         // specifically did the wrapping and so we must mimic that...
6540                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6541                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6542                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6543                         break;
6544                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6545                         w = (int) tcmod->parms[0];
6546                         h = (int) tcmod->parms[1];
6547                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6548                         f = f - floor(f);
6549                         idx = (int) floor(f * w * h);
6550                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6551                         break;
6552                 case Q3TCMOD_STRETCH:
6553                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6554                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6555                         break;
6556                 case Q3TCMOD_TRANSFORM:
6557                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6558                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6559                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6560                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6561                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6562                         break;
6563                 case Q3TCMOD_TURBULENT:
6564                         // this is handled in the RSurf_PrepareVertices function
6565                         matrix = identitymatrix;
6566                         break;
6567         }
6568         temp = *texmatrix;
6569         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6570 }
6571
6572 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6573 {
6574         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6575         char name[MAX_QPATH];
6576         skinframe_t *skinframe;
6577         unsigned char pixels[296*194];
6578         dp_strlcpy(cache->name, skinname, sizeof(cache->name));
6579         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6580         if (developer_loading.integer)
6581                 Con_Printf("loading %s\n", name);
6582         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6583         if (!skinframe || !skinframe->base)
6584         {
6585                 unsigned char *f;
6586                 fs_offset_t filesize;
6587                 skinframe = NULL;
6588                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6589                 if (f)
6590                 {
6591                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6592                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6593                         Mem_Free(f);
6594                 }
6595         }
6596         cache->skinframe = skinframe;
6597 }
6598
6599 texture_t *R_GetCurrentTexture(texture_t *t)
6600 {
6601         int i, q;
6602         const entity_render_t *ent = rsurface.entity;
6603         model_t *model = ent->model; // when calling this, ent must not be NULL
6604         q3shaderinfo_layer_tcmod_t *tcmod;
6605         float specularscale = 0.0f;
6606
6607         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6608                 return t->currentframe;
6609         t->update_lastrenderframe = r_textureframe;
6610         t->update_lastrenderentity = (void *)ent;
6611
6612         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6613                 t->camera_entity = ent->entitynumber;
6614         else
6615                 t->camera_entity = 0;
6616
6617         // switch to an alternate material if this is a q1bsp animated material
6618         {
6619                 texture_t *texture = t;
6620                 int s = rsurface.ent_skinnum;
6621                 if ((unsigned int)s >= (unsigned int)model->numskins)
6622                         s = 0;
6623                 if (model->skinscenes)
6624                 {
6625                         if (model->skinscenes[s].framecount > 1)
6626                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6627                         else
6628                                 s = model->skinscenes[s].firstframe;
6629                 }
6630                 if (s > 0)
6631                         t = t + s * model->num_surfaces;
6632                 if (t->animated)
6633                 {
6634                         // use an alternate animation if the entity's frame is not 0,
6635                         // and only if the texture has an alternate animation
6636                         if (t->animated == 2) // q2bsp
6637                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6638                         else if (rsurface.ent_alttextures && t->anim_total[1])
6639                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6640                         else
6641                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6642                 }
6643                 texture->currentframe = t;
6644         }
6645
6646         // update currentskinframe to be a qw skin or animation frame
6647         if (rsurface.ent_qwskin >= 0)
6648         {
6649                 i = rsurface.ent_qwskin;
6650                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6651                 {
6652                         r_qwskincache_size = cl.maxclients;
6653                         if (r_qwskincache)
6654                                 Mem_Free(r_qwskincache);
6655                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6656                 }
6657                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6658                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6659                 t->currentskinframe = r_qwskincache[i].skinframe;
6660                 if (t->materialshaderpass && t->currentskinframe == NULL)
6661                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6662         }
6663         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6664                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6665         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6666                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6667
6668         t->currentmaterialflags = t->basematerialflags;
6669         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6670         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6671                 t->currentalpha *= r_wateralpha.value;
6672         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6673                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6674         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6675                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6676
6677         // decide on which type of lighting to use for this surface
6678         if (rsurface.entity->render_modellight_forced)
6679                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6680         if (rsurface.entity->render_rtlight_disabled)
6681                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6682         if (rsurface.entity->render_lightgrid)
6683                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6684         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6685         {
6686                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6687                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6688                 for (q = 0; q < 3; q++)
6689                 {
6690                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6691                         t->render_modellight_lightdir_world[q] = q == 2;
6692                         t->render_modellight_lightdir_local[q] = q == 2;
6693                         t->render_modellight_ambient[q] = 1;
6694                         t->render_modellight_diffuse[q] = 0;
6695                         t->render_modellight_specular[q] = 0;
6696                         t->render_lightmap_ambient[q] = 0;
6697                         t->render_lightmap_diffuse[q] = 0;
6698                         t->render_lightmap_specular[q] = 0;
6699                         t->render_rtlight_diffuse[q] = 0;
6700                         t->render_rtlight_specular[q] = 0;
6701                 }
6702         }
6703         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6704         {
6705                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6706                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6707                 for (q = 0; q < 3; q++)
6708                 {
6709                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6710                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6711                         t->render_modellight_lightdir_world[q] = q == 2;
6712                         t->render_modellight_lightdir_local[q] = q == 2;
6713                         t->render_modellight_diffuse[q] = 0;
6714                         t->render_modellight_specular[q] = 0;
6715                         t->render_lightmap_ambient[q] = 0;
6716                         t->render_lightmap_diffuse[q] = 0;
6717                         t->render_lightmap_specular[q] = 0;
6718                         t->render_rtlight_diffuse[q] = 0;
6719                         t->render_rtlight_specular[q] = 0;
6720                 }
6721         }
6722         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6723         {
6724                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6725                 for (q = 0; q < 3; q++)
6726                 {
6727                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6728                         t->render_modellight_lightdir_world[q] = q == 2;
6729                         t->render_modellight_lightdir_local[q] = q == 2;
6730                         t->render_modellight_ambient[q] = 0;
6731                         t->render_modellight_diffuse[q] = 0;
6732                         t->render_modellight_specular[q] = 0;
6733                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6734                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6735                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6736                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6737                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6738                 }
6739         }
6740         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6741         {
6742                 // ambient + single direction light (modellight)
6743                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6744                 for (q = 0; q < 3; q++)
6745                 {
6746                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6747                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6748                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6749                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6750                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6751                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6752                         t->render_lightmap_ambient[q] = 0;
6753                         t->render_lightmap_diffuse[q] = 0;
6754                         t->render_lightmap_specular[q] = 0;
6755                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6756                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6757                 }
6758         }
6759         else
6760         {
6761                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6762                 for (q = 0; q < 3; q++)
6763                 {
6764                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6765                         t->render_modellight_lightdir_world[q] = q == 2;
6766                         t->render_modellight_lightdir_local[q] = q == 2;
6767                         t->render_modellight_ambient[q] = 0;
6768                         t->render_modellight_diffuse[q] = 0;
6769                         t->render_modellight_specular[q] = 0;
6770                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6771                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6772                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6773                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6774                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6775                 }
6776         }
6777
6778         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6779         {
6780                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6781                 // attribute, we punt it to the lightmap path and hope for the best,
6782                 // but lighting doesn't work.
6783                 //
6784                 // FIXME: this is fine for effects but CSQC polygons should be subject
6785                 // to lighting.
6786                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6787                 for (q = 0; q < 3; q++)
6788                 {
6789                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6790                         t->render_modellight_lightdir_world[q] = q == 2;
6791                         t->render_modellight_lightdir_local[q] = q == 2;
6792                         t->render_modellight_ambient[q] = 0;
6793                         t->render_modellight_diffuse[q] = 0;
6794                         t->render_modellight_specular[q] = 0;
6795                         t->render_lightmap_ambient[q] = 0;
6796                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6797                         t->render_lightmap_specular[q] = 0;
6798                         t->render_rtlight_diffuse[q] = 0;
6799                         t->render_rtlight_specular[q] = 0;
6800                 }
6801         }
6802
6803         for (q = 0; q < 3; q++)
6804         {
6805                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6806                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6807         }
6808
6809         if (rsurface.ent_flags & RENDER_ADDITIVE)
6810                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6811         else if (t->currentalpha < 1)
6812                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6813         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6814         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6815                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6816         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6817                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6818         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6819                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6820         if (t->backgroundshaderpass)
6821                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6822         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6823         {
6824                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6825                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6826         }
6827         else
6828                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6829         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6830         {
6831                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6832                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6833         }
6834         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6835                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6836
6837         // there is no tcmod
6838         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6839         {
6840                 t->currenttexmatrix = r_waterscrollmatrix;
6841                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6842         }
6843         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6844         {
6845                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6846                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6847         }
6848
6849         if (t->materialshaderpass)
6850                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6851                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6852
6853         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6854         if (t->currentskinframe->qpixels)
6855                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6856         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6857         if (!t->basetexture)
6858                 t->basetexture = r_texture_notexture;
6859         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6860         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6861         t->nmaptexture = t->currentskinframe->nmap;
6862         if (!t->nmaptexture)
6863                 t->nmaptexture = r_texture_blanknormalmap;
6864         t->glosstexture = r_texture_black;
6865         t->glowtexture = t->currentskinframe->glow;
6866         t->fogtexture = t->currentskinframe->fog;
6867         t->reflectmasktexture = t->currentskinframe->reflect;
6868         if (t->backgroundshaderpass)
6869         {
6870                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6871                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6872                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6873                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6874                 t->backgroundglosstexture = r_texture_black;
6875                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6876                 if (!t->backgroundnmaptexture)
6877                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6878                 // make sure that if glow is going to be used, both textures are not NULL
6879                 if (!t->backgroundglowtexture && t->glowtexture)
6880                         t->backgroundglowtexture = r_texture_black;
6881                 if (!t->glowtexture && t->backgroundglowtexture)
6882                         t->glowtexture = r_texture_black;
6883         }
6884         else
6885         {
6886                 t->backgroundbasetexture = r_texture_white;
6887                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6888                 t->backgroundglosstexture = r_texture_black;
6889                 t->backgroundglowtexture = NULL;
6890         }
6891         t->specularpower = r_shadow_glossexponent.value;
6892         // TODO: store reference values for these in the texture?
6893         if (r_shadow_gloss.integer > 0)
6894         {
6895                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6896                 {
6897                         if (r_shadow_glossintensity.value > 0)
6898                         {
6899                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6900                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6901                                 specularscale = r_shadow_glossintensity.value;
6902                         }
6903                 }
6904                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6905                 {
6906                         t->glosstexture = r_texture_white;
6907                         t->backgroundglosstexture = r_texture_white;
6908                         specularscale = r_shadow_gloss2intensity.value;
6909                         t->specularpower = r_shadow_gloss2exponent.value;
6910                 }
6911         }
6912         specularscale *= t->specularscalemod;
6913         t->specularpower *= t->specularpowermod;
6914
6915         // lightmaps mode looks bad with dlights using actual texturing, so turn
6916         // off the colormap and glossmap, but leave the normalmap on as it still
6917         // accurately represents the shading involved
6918         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6919         {
6920                 t->basetexture = r_texture_grey128;
6921                 t->pantstexture = r_texture_black;
6922                 t->shirttexture = r_texture_black;
6923                 if (gl_lightmaps.integer < 2)
6924                         t->nmaptexture = r_texture_blanknormalmap;
6925                 t->glosstexture = r_texture_black;
6926                 t->glowtexture = NULL;
6927                 t->fogtexture = NULL;
6928                 t->reflectmasktexture = NULL;
6929                 t->backgroundbasetexture = NULL;
6930                 if (gl_lightmaps.integer < 2)
6931                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6932                 t->backgroundglosstexture = r_texture_black;
6933                 t->backgroundglowtexture = NULL;
6934                 specularscale = 0;
6935                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6936         }
6937
6938         if (specularscale != 1.0f)
6939         {
6940                 for (q = 0; q < 3; q++)
6941                 {
6942                         t->render_modellight_specular[q] *= specularscale;
6943                         t->render_lightmap_specular[q] *= specularscale;
6944                         t->render_rtlight_specular[q] *= specularscale;
6945                 }
6946         }
6947
6948         t->currentblendfunc[0] = GL_ONE;
6949         t->currentblendfunc[1] = GL_ZERO;
6950         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6951         {
6952                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6953                 t->currentblendfunc[1] = GL_ONE;
6954         }
6955         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6956         {
6957                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6958                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6959         }
6960         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6961         {
6962                 t->currentblendfunc[0] = t->customblendfunc[0];
6963                 t->currentblendfunc[1] = t->customblendfunc[1];
6964         }
6965
6966         return t;
6967 }
6968
6969 rsurfacestate_t rsurface;
6970
6971 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6972 {
6973         model_t *model = ent->model;
6974         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6975         //      return;
6976         rsurface.entity = (entity_render_t *)ent;
6977         rsurface.skeleton = ent->skeleton;
6978         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6979         rsurface.ent_skinnum = ent->skinnum;
6980         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;
6981         rsurface.ent_flags = ent->flags;
6982         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6983                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6984         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6985         rsurface.matrix = ent->matrix;
6986         rsurface.inversematrix = ent->inversematrix;
6987         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6988         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6989         R_EntityMatrix(&rsurface.matrix);
6990         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6991         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6992         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6993         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6994         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6995         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6996         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6997         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6998         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6999         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7000         if (ent->model->brush.submodel && !prepass)
7001         {
7002                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7003                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7004         }
7005         // if the animcache code decided it should use the shader path, skip the deform step
7006         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7007         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7008         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7009         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7010         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7011         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7012         {
7013                 if (ent->animcache_vertex3f)
7014                 {
7015                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7016                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7017                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7018                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7019                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7020                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7021                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7022                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7023                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7024                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7025                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7026                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7027                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7028                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7029                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7030                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7031                 }
7032                 else if (wanttangents)
7033                 {
7034                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7035                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7036                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7037                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7038                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7039                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7040                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7041                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7042                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7043                         rsurface.modelvertex3f_vertexbuffer = NULL;
7044                         rsurface.modelvertex3f_bufferoffset = 0;
7045                         rsurface.modelvertex3f_vertexbuffer = 0;
7046                         rsurface.modelvertex3f_bufferoffset = 0;
7047                         rsurface.modelsvector3f_vertexbuffer = 0;
7048                         rsurface.modelsvector3f_bufferoffset = 0;
7049                         rsurface.modeltvector3f_vertexbuffer = 0;
7050                         rsurface.modeltvector3f_bufferoffset = 0;
7051                         rsurface.modelnormal3f_vertexbuffer = 0;
7052                         rsurface.modelnormal3f_bufferoffset = 0;
7053                 }
7054                 else if (wantnormals)
7055                 {
7056                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7057                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7058                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7059                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7060                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7061                         rsurface.modelsvector3f = NULL;
7062                         rsurface.modeltvector3f = NULL;
7063                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7064                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7065                         rsurface.modelvertex3f_vertexbuffer = NULL;
7066                         rsurface.modelvertex3f_bufferoffset = 0;
7067                         rsurface.modelvertex3f_vertexbuffer = 0;
7068                         rsurface.modelvertex3f_bufferoffset = 0;
7069                         rsurface.modelsvector3f_vertexbuffer = 0;
7070                         rsurface.modelsvector3f_bufferoffset = 0;
7071                         rsurface.modeltvector3f_vertexbuffer = 0;
7072                         rsurface.modeltvector3f_bufferoffset = 0;
7073                         rsurface.modelnormal3f_vertexbuffer = 0;
7074                         rsurface.modelnormal3f_bufferoffset = 0;
7075                 }
7076                 else
7077                 {
7078                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7079                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7080                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7081                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7082                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7083                         rsurface.modelsvector3f = NULL;
7084                         rsurface.modeltvector3f = NULL;
7085                         rsurface.modelnormal3f = NULL;
7086                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7087                         rsurface.modelvertex3f_vertexbuffer = NULL;
7088                         rsurface.modelvertex3f_bufferoffset = 0;
7089                         rsurface.modelvertex3f_vertexbuffer = 0;
7090                         rsurface.modelvertex3f_bufferoffset = 0;
7091                         rsurface.modelsvector3f_vertexbuffer = 0;
7092                         rsurface.modelsvector3f_bufferoffset = 0;
7093                         rsurface.modeltvector3f_vertexbuffer = 0;
7094                         rsurface.modeltvector3f_bufferoffset = 0;
7095                         rsurface.modelnormal3f_vertexbuffer = 0;
7096                         rsurface.modelnormal3f_bufferoffset = 0;
7097                 }
7098                 rsurface.modelgeneratedvertex = true;
7099         }
7100         else
7101         {
7102                 if (rsurface.entityskeletaltransform3x4)
7103                 {
7104                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7105                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7106                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7107                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7108                 }
7109                 else
7110                 {
7111                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7112                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7113                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7114                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7115                 }
7116                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7117                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7118                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7119                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7120                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7121                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7122                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7123                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7124                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7125                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7126                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7127                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7128                 rsurface.modelgeneratedvertex = false;
7129         }
7130         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7131         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7132         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7133         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7134         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7135         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7136         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7137         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7138         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7139         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7140         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7141         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7142         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7143         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7144         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7145         rsurface.modelelement3i = model->surfmesh.data_element3i;
7146         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7147         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7148         rsurface.modelelement3s = model->surfmesh.data_element3s;
7149         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7150         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7151         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7152         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7153         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7154         rsurface.modelsurfaces = model->data_surfaces;
7155         rsurface.batchgeneratedvertex = false;
7156         rsurface.batchfirstvertex = 0;
7157         rsurface.batchnumvertices = 0;
7158         rsurface.batchfirsttriangle = 0;
7159         rsurface.batchnumtriangles = 0;
7160         rsurface.batchvertex3f  = NULL;
7161         rsurface.batchvertex3f_vertexbuffer = NULL;
7162         rsurface.batchvertex3f_bufferoffset = 0;
7163         rsurface.batchsvector3f = NULL;
7164         rsurface.batchsvector3f_vertexbuffer = NULL;
7165         rsurface.batchsvector3f_bufferoffset = 0;
7166         rsurface.batchtvector3f = NULL;
7167         rsurface.batchtvector3f_vertexbuffer = NULL;
7168         rsurface.batchtvector3f_bufferoffset = 0;
7169         rsurface.batchnormal3f  = NULL;
7170         rsurface.batchnormal3f_vertexbuffer = NULL;
7171         rsurface.batchnormal3f_bufferoffset = 0;
7172         rsurface.batchlightmapcolor4f = NULL;
7173         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7174         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7175         rsurface.batchtexcoordtexture2f = NULL;
7176         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7177         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7178         rsurface.batchtexcoordlightmap2f = NULL;
7179         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7180         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7181         rsurface.batchskeletalindex4ub = NULL;
7182         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7183         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7184         rsurface.batchskeletalweight4ub = NULL;
7185         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7186         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7187         rsurface.batchelement3i = NULL;
7188         rsurface.batchelement3i_indexbuffer = NULL;
7189         rsurface.batchelement3i_bufferoffset = 0;
7190         rsurface.batchelement3s = NULL;
7191         rsurface.batchelement3s_indexbuffer = NULL;
7192         rsurface.batchelement3s_bufferoffset = 0;
7193         rsurface.forcecurrenttextureupdate = false;
7194 }
7195
7196 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qbool wantnormals, qbool wanttangents)
7197 {
7198         rsurface.entity = r_refdef.scene.worldentity;
7199         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7200                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7201                 // A better approach could be making this copy only once per frame.
7202                 static entity_render_t custom_entity;
7203                 int q;
7204                 custom_entity = *rsurface.entity;
7205                 for (q = 0; q < 3; ++q) {
7206                         float colormod = q == 0 ? r : q == 1 ? g : b;
7207                         custom_entity.render_fullbright[q] *= colormod;
7208                         custom_entity.render_modellight_ambient[q] *= colormod;
7209                         custom_entity.render_modellight_diffuse[q] *= colormod;
7210                         custom_entity.render_lightmap_ambient[q] *= colormod;
7211                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7212                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7213                 }
7214                 custom_entity.alpha *= a;
7215                 rsurface.entity = &custom_entity;
7216         }
7217         rsurface.skeleton = NULL;
7218         rsurface.ent_skinnum = 0;
7219         rsurface.ent_qwskin = -1;
7220         rsurface.ent_flags = entflags;
7221         rsurface.shadertime = r_refdef.scene.time - shadertime;
7222         rsurface.modelnumvertices = numvertices;
7223         rsurface.modelnumtriangles = numtriangles;
7224         rsurface.matrix = *matrix;
7225         rsurface.inversematrix = *inversematrix;
7226         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7227         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7228         R_EntityMatrix(&rsurface.matrix);
7229         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7230         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7231         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7232         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7233         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7234         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7235         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7236         rsurface.frameblend[0].lerp = 1;
7237         rsurface.ent_alttextures = false;
7238         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7239         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7240         rsurface.entityskeletaltransform3x4 = NULL;
7241         rsurface.entityskeletaltransform3x4buffer = NULL;
7242         rsurface.entityskeletaltransform3x4offset = 0;
7243         rsurface.entityskeletaltransform3x4size = 0;
7244         rsurface.entityskeletalnumtransforms = 0;
7245         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7246         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7247         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7248         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7249         if (wanttangents)
7250         {
7251                 rsurface.modelvertex3f = (float *)vertex3f;
7252                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7253                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7254                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7255         }
7256         else if (wantnormals)
7257         {
7258                 rsurface.modelvertex3f = (float *)vertex3f;
7259                 rsurface.modelsvector3f = NULL;
7260                 rsurface.modeltvector3f = NULL;
7261                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7262         }
7263         else
7264         {
7265                 rsurface.modelvertex3f = (float *)vertex3f;
7266                 rsurface.modelsvector3f = NULL;
7267                 rsurface.modeltvector3f = NULL;
7268                 rsurface.modelnormal3f = NULL;
7269         }
7270         rsurface.modelvertex3f_vertexbuffer = 0;
7271         rsurface.modelvertex3f_bufferoffset = 0;
7272         rsurface.modelsvector3f_vertexbuffer = 0;
7273         rsurface.modelsvector3f_bufferoffset = 0;
7274         rsurface.modeltvector3f_vertexbuffer = 0;
7275         rsurface.modeltvector3f_bufferoffset = 0;
7276         rsurface.modelnormal3f_vertexbuffer = 0;
7277         rsurface.modelnormal3f_bufferoffset = 0;
7278         rsurface.modelgeneratedvertex = true;
7279         rsurface.modellightmapcolor4f  = (float *)color4f;
7280         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7281         rsurface.modellightmapcolor4f_bufferoffset = 0;
7282         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7283         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7284         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7285         rsurface.modeltexcoordlightmap2f  = NULL;
7286         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7287         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7288         rsurface.modelskeletalindex4ub = NULL;
7289         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7290         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7291         rsurface.modelskeletalweight4ub = NULL;
7292         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7293         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7294         rsurface.modelelement3i = (int *)element3i;
7295         rsurface.modelelement3i_indexbuffer = NULL;
7296         rsurface.modelelement3i_bufferoffset = 0;
7297         rsurface.modelelement3s = (unsigned short *)element3s;
7298         rsurface.modelelement3s_indexbuffer = NULL;
7299         rsurface.modelelement3s_bufferoffset = 0;
7300         rsurface.modellightmapoffsets = NULL;
7301         rsurface.modelsurfaces = NULL;
7302         rsurface.batchgeneratedvertex = false;
7303         rsurface.batchfirstvertex = 0;
7304         rsurface.batchnumvertices = 0;
7305         rsurface.batchfirsttriangle = 0;
7306         rsurface.batchnumtriangles = 0;
7307         rsurface.batchvertex3f  = NULL;
7308         rsurface.batchvertex3f_vertexbuffer = NULL;
7309         rsurface.batchvertex3f_bufferoffset = 0;
7310         rsurface.batchsvector3f = NULL;
7311         rsurface.batchsvector3f_vertexbuffer = NULL;
7312         rsurface.batchsvector3f_bufferoffset = 0;
7313         rsurface.batchtvector3f = NULL;
7314         rsurface.batchtvector3f_vertexbuffer = NULL;
7315         rsurface.batchtvector3f_bufferoffset = 0;
7316         rsurface.batchnormal3f  = NULL;
7317         rsurface.batchnormal3f_vertexbuffer = NULL;
7318         rsurface.batchnormal3f_bufferoffset = 0;
7319         rsurface.batchlightmapcolor4f = NULL;
7320         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7321         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7322         rsurface.batchtexcoordtexture2f = NULL;
7323         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7324         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7325         rsurface.batchtexcoordlightmap2f = NULL;
7326         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7327         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7328         rsurface.batchskeletalindex4ub = NULL;
7329         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7330         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7331         rsurface.batchskeletalweight4ub = NULL;
7332         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7333         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7334         rsurface.batchelement3i = NULL;
7335         rsurface.batchelement3i_indexbuffer = NULL;
7336         rsurface.batchelement3i_bufferoffset = 0;
7337         rsurface.batchelement3s = NULL;
7338         rsurface.batchelement3s_indexbuffer = NULL;
7339         rsurface.batchelement3s_bufferoffset = 0;
7340         rsurface.forcecurrenttextureupdate = true;
7341
7342         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7343         {
7344                 if ((wantnormals || wanttangents) && !normal3f)
7345                 {
7346                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7347                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7348                 }
7349                 if (wanttangents && !svector3f)
7350                 {
7351                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7352                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7353                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7354                 }
7355         }
7356 }
7357
7358 float RSurf_FogPoint(const float *v)
7359 {
7360         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7361         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7362         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7363         float FogHeightFade = r_refdef.fogheightfade;
7364         float fogfrac;
7365         unsigned int fogmasktableindex;
7366         if (r_refdef.fogplaneviewabove)
7367                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7368         else
7369                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7370         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7371         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7372 }
7373
7374 float RSurf_FogVertex(const float *v)
7375 {
7376         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7377         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7378         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7379         float FogHeightFade = rsurface.fogheightfade;
7380         float fogfrac;
7381         unsigned int fogmasktableindex;
7382         if (r_refdef.fogplaneviewabove)
7383                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7384         else
7385                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7386         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7387         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7388 }
7389
7390 void RSurf_UploadBuffersForBatch(void)
7391 {
7392         // 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)
7393         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7394         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7395                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7396         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7397                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7398         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7399                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7400         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7401                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7402         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7403                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7404         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7405                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7406         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7407                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7408         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7409                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7410         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7411                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7412
7413         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7414                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7415         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7416                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7417
7418         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7419         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7420         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7421         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7422         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7423         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7424         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7425         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7426         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7427         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7428 }
7429
7430 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7431 {
7432         int i;
7433         for (i = 0;i < numelements;i++)
7434                 outelement3i[i] = inelement3i[i] + adjust;
7435 }
7436
7437 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7438 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7439 {
7440         int deformindex;
7441         int firsttriangle;
7442         int numtriangles;
7443         int firstvertex;
7444         int endvertex;
7445         int numvertices;
7446         int surfacefirsttriangle;
7447         int surfacenumtriangles;
7448         int surfacefirstvertex;
7449         int surfaceendvertex;
7450         int surfacenumvertices;
7451         int batchnumsurfaces = texturenumsurfaces;
7452         int batchnumvertices;
7453         int batchnumtriangles;
7454         int i, j;
7455         qbool gaps;
7456         qbool dynamicvertex;
7457         float amplitude;
7458         float animpos;
7459         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7460         float waveparms[4];
7461         unsigned char *ub;
7462         q3shaderinfo_deform_t *deform;
7463         const msurface_t *surface, *firstsurface;
7464         if (!texturenumsurfaces)
7465                 return;
7466         // find vertex range of this surface batch
7467         gaps = false;
7468         firstsurface = texturesurfacelist[0];
7469         firsttriangle = firstsurface->num_firsttriangle;
7470         batchnumvertices = 0;
7471         batchnumtriangles = 0;
7472         firstvertex = endvertex = firstsurface->num_firstvertex;
7473         for (i = 0;i < texturenumsurfaces;i++)
7474         {
7475                 surface = texturesurfacelist[i];
7476                 if (surface != firstsurface + i)
7477                         gaps = true;
7478                 surfacefirstvertex = surface->num_firstvertex;
7479                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7480                 surfacenumvertices = surface->num_vertices;
7481                 surfacenumtriangles = surface->num_triangles;
7482                 if (firstvertex > surfacefirstvertex)
7483                         firstvertex = surfacefirstvertex;
7484                 if (endvertex < surfaceendvertex)
7485                         endvertex = surfaceendvertex;
7486                 batchnumvertices += surfacenumvertices;
7487                 batchnumtriangles += surfacenumtriangles;
7488         }
7489
7490         r_refdef.stats[r_stat_batch_batches]++;
7491         if (gaps)
7492                 r_refdef.stats[r_stat_batch_withgaps]++;
7493         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7494         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7495         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7496
7497         // we now know the vertex range used, and if there are any gaps in it
7498         rsurface.batchfirstvertex = firstvertex;
7499         rsurface.batchnumvertices = endvertex - firstvertex;
7500         rsurface.batchfirsttriangle = firsttriangle;
7501         rsurface.batchnumtriangles = batchnumtriangles;
7502
7503         // check if any dynamic vertex processing must occur
7504         dynamicvertex = false;
7505
7506         // we must use vertexbuffers for rendering, we can upload vertex buffers
7507         // easily enough but if the basevertex is non-zero it becomes more
7508         // difficult, so force dynamicvertex path in that case - it's suboptimal
7509         // but the most optimal case is to have the geometry sources provide their
7510         // own anyway.
7511         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7512                 dynamicvertex = true;
7513
7514         // a cvar to force the dynamic vertex path to be taken, for debugging
7515         if (r_batch_debugdynamicvertexpath.integer)
7516         {
7517                 if (!dynamicvertex)
7518                 {
7519                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7520                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7521                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7522                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7523                 }
7524                 dynamicvertex = true;
7525         }
7526
7527         // if there is a chance of animated vertex colors, it's a dynamic batch
7528         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7529         {
7530                 if (!dynamicvertex)
7531                 {
7532                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7533                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7534                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7535                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7536                 }
7537                 dynamicvertex = true;
7538         }
7539
7540         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7541         {
7542                 switch (deform->deform)
7543                 {
7544                 default:
7545                 case Q3DEFORM_PROJECTIONSHADOW:
7546                 case Q3DEFORM_TEXT0:
7547                 case Q3DEFORM_TEXT1:
7548                 case Q3DEFORM_TEXT2:
7549                 case Q3DEFORM_TEXT3:
7550                 case Q3DEFORM_TEXT4:
7551                 case Q3DEFORM_TEXT5:
7552                 case Q3DEFORM_TEXT6:
7553                 case Q3DEFORM_TEXT7:
7554                 case Q3DEFORM_NONE:
7555                         break;
7556                 case Q3DEFORM_AUTOSPRITE:
7557                         if (!dynamicvertex)
7558                         {
7559                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7560                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7561                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7562                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7563                         }
7564                         dynamicvertex = true;
7565                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7566                         break;
7567                 case Q3DEFORM_AUTOSPRITE2:
7568                         if (!dynamicvertex)
7569                         {
7570                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7571                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7572                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7573                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7574                         }
7575                         dynamicvertex = true;
7576                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7577                         break;
7578                 case Q3DEFORM_NORMAL:
7579                         if (!dynamicvertex)
7580                         {
7581                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7582                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7583                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7584                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7585                         }
7586                         dynamicvertex = true;
7587                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7588                         break;
7589                 case Q3DEFORM_WAVE:
7590                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7591                                 break; // if wavefunc is a nop, ignore this transform
7592                         if (!dynamicvertex)
7593                         {
7594                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7595                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7596                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7597                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7598                         }
7599                         dynamicvertex = true;
7600                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7601                         break;
7602                 case Q3DEFORM_BULGE:
7603                         if (!dynamicvertex)
7604                         {
7605                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7606                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7607                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7608                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7609                         }
7610                         dynamicvertex = true;
7611                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7612                         break;
7613                 case Q3DEFORM_MOVE:
7614                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7615                                 break; // if wavefunc is a nop, ignore this transform
7616                         if (!dynamicvertex)
7617                         {
7618                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7619                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7620                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7621                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7622                         }
7623                         dynamicvertex = true;
7624                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7625                         break;
7626                 }
7627         }
7628         if (rsurface.texture->materialshaderpass)
7629         {
7630                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7631                 {
7632                 default:
7633                 case Q3TCGEN_TEXTURE:
7634                         break;
7635                 case Q3TCGEN_LIGHTMAP:
7636                         if (!dynamicvertex)
7637                         {
7638                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7639                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7640                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7641                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7642                         }
7643                         dynamicvertex = true;
7644                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7645                         break;
7646                 case Q3TCGEN_VECTOR:
7647                         if (!dynamicvertex)
7648                         {
7649                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7650                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7651                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7652                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7653                         }
7654                         dynamicvertex = true;
7655                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7656                         break;
7657                 case Q3TCGEN_ENVIRONMENT:
7658                         if (!dynamicvertex)
7659                         {
7660                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7661                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7662                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7663                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7664                         }
7665                         dynamicvertex = true;
7666                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7667                         break;
7668                 }
7669                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7670                 {
7671                         if (!dynamicvertex)
7672                         {
7673                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7674                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7675                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7676                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7677                         }
7678                         dynamicvertex = true;
7679                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7680                 }
7681         }
7682
7683         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7684         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7685         // we ensure this by treating the vertex batch as dynamic...
7686         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7687         {
7688                 if (!dynamicvertex)
7689                 {
7690                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7691                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7692                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7693                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7694                 }
7695                 dynamicvertex = true;
7696         }
7697
7698         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7699         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7700                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7701
7702         rsurface.batchvertex3f = rsurface.modelvertex3f;
7703         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7704         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7705         rsurface.batchsvector3f = rsurface.modelsvector3f;
7706         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7707         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7708         rsurface.batchtvector3f = rsurface.modeltvector3f;
7709         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7710         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7711         rsurface.batchnormal3f = rsurface.modelnormal3f;
7712         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7713         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7714         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7715         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7716         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7717         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7718         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7719         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7720         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7721         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7722         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7723         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7724         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7725         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7726         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7727         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7728         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7729         rsurface.batchelement3i = rsurface.modelelement3i;
7730         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7731         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7732         rsurface.batchelement3s = rsurface.modelelement3s;
7733         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7734         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7735         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7736         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7737         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7738         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7739         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7740
7741         // if any dynamic vertex processing has to occur in software, we copy the
7742         // entire surface list together before processing to rebase the vertices
7743         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7744         //
7745         // if any gaps exist and we do not have a static vertex buffer, we have to
7746         // copy the surface list together to avoid wasting upload bandwidth on the
7747         // vertices in the gaps.
7748         //
7749         // if gaps exist and we have a static vertex buffer, we can choose whether
7750         // to combine the index buffer ranges into one dynamic index buffer or
7751         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7752         //
7753         // in many cases the batch is reduced to one draw call.
7754
7755         rsurface.batchmultidraw = false;
7756         rsurface.batchmultidrawnumsurfaces = 0;
7757         rsurface.batchmultidrawsurfacelist = NULL;
7758
7759         if (!dynamicvertex)
7760         {
7761                 // static vertex data, just set pointers...
7762                 rsurface.batchgeneratedvertex = false;
7763                 // if there are gaps, we want to build a combined index buffer,
7764                 // otherwise use the original static buffer with an appropriate offset
7765                 if (gaps)
7766                 {
7767                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7768                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7769                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7770                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7771                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7772                         {
7773                                 rsurface.batchmultidraw = true;
7774                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7775                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7776                                 return;
7777                         }
7778                         // build a new triangle elements array for this batch
7779                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7780                         rsurface.batchfirsttriangle = 0;
7781                         numtriangles = 0;
7782                         for (i = 0;i < texturenumsurfaces;i++)
7783                         {
7784                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7785                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7786                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7787                                 numtriangles += surfacenumtriangles;
7788                         }
7789                         rsurface.batchelement3i_indexbuffer = NULL;
7790                         rsurface.batchelement3i_bufferoffset = 0;
7791                         rsurface.batchelement3s = NULL;
7792                         rsurface.batchelement3s_indexbuffer = NULL;
7793                         rsurface.batchelement3s_bufferoffset = 0;
7794                         if (endvertex <= 65536)
7795                         {
7796                                 // make a 16bit (unsigned short) index array if possible
7797                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7798                                 for (i = 0;i < numtriangles*3;i++)
7799                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7800                         }
7801                 }
7802                 else
7803                 {
7804                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7805                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7806                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7807                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7808                 }
7809                 return;
7810         }
7811
7812         // something needs software processing, do it for real...
7813         // we only directly handle separate array data in this case and then
7814         // generate interleaved data if needed...
7815         rsurface.batchgeneratedvertex = true;
7816         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7817         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7818         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7819         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7820
7821         // now copy the vertex data into a combined array and make an index array
7822         // (this is what Quake3 does all the time)
7823         // we also apply any skeletal animation here that would have been done in
7824         // the vertex shader, because most of the dynamic vertex animation cases
7825         // need actual vertex positions and normals
7826         //if (dynamicvertex)
7827         {
7828                 rsurface.batchvertex3f = NULL;
7829                 rsurface.batchvertex3f_vertexbuffer = NULL;
7830                 rsurface.batchvertex3f_bufferoffset = 0;
7831                 rsurface.batchsvector3f = NULL;
7832                 rsurface.batchsvector3f_vertexbuffer = NULL;
7833                 rsurface.batchsvector3f_bufferoffset = 0;
7834                 rsurface.batchtvector3f = NULL;
7835                 rsurface.batchtvector3f_vertexbuffer = NULL;
7836                 rsurface.batchtvector3f_bufferoffset = 0;
7837                 rsurface.batchnormal3f = NULL;
7838                 rsurface.batchnormal3f_vertexbuffer = NULL;
7839                 rsurface.batchnormal3f_bufferoffset = 0;
7840                 rsurface.batchlightmapcolor4f = NULL;
7841                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7842                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7843                 rsurface.batchtexcoordtexture2f = NULL;
7844                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7845                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7846                 rsurface.batchtexcoordlightmap2f = NULL;
7847                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7848                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7849                 rsurface.batchskeletalindex4ub = NULL;
7850                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7851                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7852                 rsurface.batchskeletalweight4ub = NULL;
7853                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7854                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7855                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7856                 rsurface.batchelement3i_indexbuffer = NULL;
7857                 rsurface.batchelement3i_bufferoffset = 0;
7858                 rsurface.batchelement3s = NULL;
7859                 rsurface.batchelement3s_indexbuffer = NULL;
7860                 rsurface.batchelement3s_bufferoffset = 0;
7861                 rsurface.batchskeletaltransform3x4buffer = NULL;
7862                 rsurface.batchskeletaltransform3x4offset = 0;
7863                 rsurface.batchskeletaltransform3x4size = 0;
7864                 // we'll only be setting up certain arrays as needed
7865                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7866                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7867                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7868                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7869                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7870                 {
7871                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7872                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7873                 }
7874                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7875                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7876                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7877                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7878                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7879                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7880                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7881                 {
7882                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7883                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7884                 }
7885                 numvertices = 0;
7886                 numtriangles = 0;
7887                 for (i = 0;i < texturenumsurfaces;i++)
7888                 {
7889                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7890                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7891                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7892                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7893                         // copy only the data requested
7894                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7895                         {
7896                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7897                                 {
7898                                         if (rsurface.batchvertex3f)
7899                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7900                                         else
7901                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7902                                 }
7903                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7904                                 {
7905                                         if (rsurface.modelnormal3f)
7906                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7907                                         else
7908                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7909                                 }
7910                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7911                                 {
7912                                         if (rsurface.modelsvector3f)
7913                                         {
7914                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7915                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7916                                         }
7917                                         else
7918                                         {
7919                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7920                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7921                                         }
7922                                 }
7923                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7924                                 {
7925                                         if (rsurface.modellightmapcolor4f)
7926                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7927                                         else
7928                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7929                                 }
7930                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7931                                 {
7932                                         if (rsurface.modeltexcoordtexture2f)
7933                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7934                                         else
7935                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7936                                 }
7937                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7938                                 {
7939                                         if (rsurface.modeltexcoordlightmap2f)
7940                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7941                                         else
7942                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7943                                 }
7944                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7945                                 {
7946                                         if (rsurface.modelskeletalindex4ub)
7947                                         {
7948                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7949                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7950                                         }
7951                                         else
7952                                         {
7953                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7954                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7955                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7956                                                 for (j = 0;j < surfacenumvertices;j++)
7957                                                         ub[j*4] = 255;
7958                                         }
7959                                 }
7960                         }
7961                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7962                         numvertices += surfacenumvertices;
7963                         numtriangles += surfacenumtriangles;
7964                 }
7965
7966                 // generate a 16bit index array as well if possible
7967                 // (in general, dynamic batches fit)
7968                 if (numvertices <= 65536)
7969                 {
7970                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7971                         for (i = 0;i < numtriangles*3;i++)
7972                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7973                 }
7974
7975                 // since we've copied everything, the batch now starts at 0
7976                 rsurface.batchfirstvertex = 0;
7977                 rsurface.batchnumvertices = batchnumvertices;
7978                 rsurface.batchfirsttriangle = 0;
7979                 rsurface.batchnumtriangles = batchnumtriangles;
7980         }
7981
7982         // apply skeletal animation that would have been done in the vertex shader
7983         if (rsurface.batchskeletaltransform3x4)
7984         {
7985                 const unsigned char *si;
7986                 const unsigned char *sw;
7987                 const float *t[4];
7988                 const float *b = rsurface.batchskeletaltransform3x4;
7989                 float *vp, *vs, *vt, *vn;
7990                 float w[4];
7991                 float m[3][4], n[3][4];
7992                 float tp[3], ts[3], tt[3], tn[3];
7993                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7994                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7995                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7996                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7997                 si = rsurface.batchskeletalindex4ub;
7998                 sw = rsurface.batchskeletalweight4ub;
7999                 vp = rsurface.batchvertex3f;
8000                 vs = rsurface.batchsvector3f;
8001                 vt = rsurface.batchtvector3f;
8002                 vn = rsurface.batchnormal3f;
8003                 memset(m[0], 0, sizeof(m));
8004                 memset(n[0], 0, sizeof(n));
8005                 for (i = 0;i < batchnumvertices;i++)
8006                 {
8007                         t[0] = b + si[0]*12;
8008                         if (sw[0] == 255)
8009                         {
8010                                 // common case - only one matrix
8011                                 m[0][0] = t[0][ 0];
8012                                 m[0][1] = t[0][ 1];
8013                                 m[0][2] = t[0][ 2];
8014                                 m[0][3] = t[0][ 3];
8015                                 m[1][0] = t[0][ 4];
8016                                 m[1][1] = t[0][ 5];
8017                                 m[1][2] = t[0][ 6];
8018                                 m[1][3] = t[0][ 7];
8019                                 m[2][0] = t[0][ 8];
8020                                 m[2][1] = t[0][ 9];
8021                                 m[2][2] = t[0][10];
8022                                 m[2][3] = t[0][11];
8023                         }
8024                         else if (sw[2] + sw[3])
8025                         {
8026                                 // blend 4 matrices
8027                                 t[1] = b + si[1]*12;
8028                                 t[2] = b + si[2]*12;
8029                                 t[3] = b + si[3]*12;
8030                                 w[0] = sw[0] * (1.0f / 255.0f);
8031                                 w[1] = sw[1] * (1.0f / 255.0f);
8032                                 w[2] = sw[2] * (1.0f / 255.0f);
8033                                 w[3] = sw[3] * (1.0f / 255.0f);
8034                                 // blend the matrices
8035                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8036                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8037                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8038                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8039                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8040                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8041                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8042                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8043                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8044                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8045                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8046                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8047                         }
8048                         else
8049                         {
8050                                 // blend 2 matrices
8051                                 t[1] = b + si[1]*12;
8052                                 w[0] = sw[0] * (1.0f / 255.0f);
8053                                 w[1] = sw[1] * (1.0f / 255.0f);
8054                                 // blend the matrices
8055                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8056                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8057                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8058                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8059                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8060                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8061                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8062                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8063                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8064                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8065                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8066                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8067                         }
8068                         si += 4;
8069                         sw += 4;
8070                         // modify the vertex
8071                         VectorCopy(vp, tp);
8072                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8073                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8074                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8075                         vp += 3;
8076                         if (vn)
8077                         {
8078                                 // the normal transformation matrix is a set of cross products...
8079                                 CrossProduct(m[1], m[2], n[0]);
8080                                 CrossProduct(m[2], m[0], n[1]);
8081                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8082                                 VectorCopy(vn, tn);
8083                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8084                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8085                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8086                                 VectorNormalize(vn);
8087                                 vn += 3;
8088                                 if (vs)
8089                                 {
8090                                         VectorCopy(vs, ts);
8091                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8092                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8093                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8094                                         VectorNormalize(vs);
8095                                         vs += 3;
8096                                         VectorCopy(vt, tt);
8097                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8098                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8099                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8100                                         VectorNormalize(vt);
8101                                         vt += 3;
8102                                 }
8103                         }
8104                 }
8105                 rsurface.batchskeletaltransform3x4 = NULL;
8106                 rsurface.batchskeletalnumtransforms = 0;
8107         }
8108
8109         // q1bsp surfaces rendered in vertex color mode have to have colors
8110         // calculated based on lightstyles
8111         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8112         {
8113                 // generate color arrays for the surfaces in this list
8114                 int c[4];
8115                 int scale;
8116                 int size3;
8117                 const int *offsets;
8118                 const unsigned char *lm;
8119                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8120                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8121                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8122                 numvertices = 0;
8123                 for (i = 0;i < texturenumsurfaces;i++)
8124                 {
8125                         surface = texturesurfacelist[i];
8126                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8127                         surfacenumvertices = surface->num_vertices;
8128                         if (surface->lightmapinfo->samples)
8129                         {
8130                                 for (j = 0;j < surfacenumvertices;j++)
8131                                 {
8132                                         lm = surface->lightmapinfo->samples + offsets[j];
8133                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8134                                         VectorScale(lm, scale, c);
8135                                         if (surface->lightmapinfo->styles[1] != 255)
8136                                         {
8137                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8138                                                 lm += size3;
8139                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8140                                                 VectorMA(c, scale, lm, c);
8141                                                 if (surface->lightmapinfo->styles[2] != 255)
8142                                                 {
8143                                                         lm += size3;
8144                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8145                                                         VectorMA(c, scale, lm, c);
8146                                                         if (surface->lightmapinfo->styles[3] != 255)
8147                                                         {
8148                                                                 lm += size3;
8149                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8150                                                                 VectorMA(c, scale, lm, c);
8151                                                         }
8152                                                 }
8153                                         }
8154                                         c[0] >>= 7;
8155                                         c[1] >>= 7;
8156                                         c[2] >>= 7;
8157                                         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);
8158                                         numvertices++;
8159                                 }
8160                         }
8161                         else
8162                         {
8163                                 for (j = 0;j < surfacenumvertices;j++)
8164                                 {
8165                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8166                                         numvertices++;
8167                                 }
8168                         }
8169                 }
8170         }
8171
8172         // if vertices are deformed (sprite flares and things in maps, possibly
8173         // water waves, bulges and other deformations), modify the copied vertices
8174         // in place
8175         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8176         {
8177                 float scale;
8178                 switch (deform->deform)
8179                 {
8180                 default:
8181                 case Q3DEFORM_PROJECTIONSHADOW:
8182                 case Q3DEFORM_TEXT0:
8183                 case Q3DEFORM_TEXT1:
8184                 case Q3DEFORM_TEXT2:
8185                 case Q3DEFORM_TEXT3:
8186                 case Q3DEFORM_TEXT4:
8187                 case Q3DEFORM_TEXT5:
8188                 case Q3DEFORM_TEXT6:
8189                 case Q3DEFORM_TEXT7:
8190                 case Q3DEFORM_NONE:
8191                         break;
8192                 case Q3DEFORM_AUTOSPRITE:
8193                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8194                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8195                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8196                         VectorNormalize(newforward);
8197                         VectorNormalize(newright);
8198                         VectorNormalize(newup);
8199 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8200 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8201 //                      rsurface.batchvertex3f_bufferoffset = 0;
8202 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8203 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8204 //                      rsurface.batchsvector3f_bufferoffset = 0;
8205 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8206 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8207 //                      rsurface.batchtvector3f_bufferoffset = 0;
8208 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8209 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8210 //                      rsurface.batchnormal3f_bufferoffset = 0;
8211                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8212                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8213                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8214                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8215                                 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);
8216                         // a single autosprite surface can contain multiple sprites...
8217                         for (j = 0;j < batchnumvertices - 3;j += 4)
8218                         {
8219                                 VectorClear(center);
8220                                 for (i = 0;i < 4;i++)
8221                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8222                                 VectorScale(center, 0.25f, center);
8223                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8224                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8225                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8226                                 for (i = 0;i < 4;i++)
8227                                 {
8228                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8229                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8230                                 }
8231                         }
8232                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8233                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8234                         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);
8235                         break;
8236                 case Q3DEFORM_AUTOSPRITE2:
8237                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8238                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8239                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8240                         VectorNormalize(newforward);
8241                         VectorNormalize(newright);
8242                         VectorNormalize(newup);
8243 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8244 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8245 //                      rsurface.batchvertex3f_bufferoffset = 0;
8246                         {
8247                                 const float *v1, *v2;
8248                                 vec3_t start, end;
8249                                 float f, l;
8250                                 struct
8251                                 {
8252                                         float length2;
8253                                         const float *v1;
8254                                         const float *v2;
8255                                 }
8256                                 shortest[2];
8257                                 memset(shortest, 0, sizeof(shortest));
8258                                 // a single autosprite surface can contain multiple sprites...
8259                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8260                                 {
8261                                         VectorClear(center);
8262                                         for (i = 0;i < 4;i++)
8263                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8264                                         VectorScale(center, 0.25f, center);
8265                                         // find the two shortest edges, then use them to define the
8266                                         // axis vectors for rotating around the central axis
8267                                         for (i = 0;i < 6;i++)
8268                                         {
8269                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8270                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8271                                                 l = VectorDistance2(v1, v2);
8272                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8273                                                 if (v1[2] != v2[2])
8274                                                         l += (1.0f / 1024.0f);
8275                                                 if (shortest[0].length2 > l || i == 0)
8276                                                 {
8277                                                         shortest[1] = shortest[0];
8278                                                         shortest[0].length2 = l;
8279                                                         shortest[0].v1 = v1;
8280                                                         shortest[0].v2 = v2;
8281                                                 }
8282                                                 else if (shortest[1].length2 > l || i == 1)
8283                                                 {
8284                                                         shortest[1].length2 = l;
8285                                                         shortest[1].v1 = v1;
8286                                                         shortest[1].v2 = v2;
8287                                                 }
8288                                         }
8289                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8290                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8291                                         // this calculates the right vector from the shortest edge
8292                                         // and the up vector from the edge midpoints
8293                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8294                                         VectorNormalize(right);
8295                                         VectorSubtract(end, start, up);
8296                                         VectorNormalize(up);
8297                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8298                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8299                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8300                                         VectorNegate(forward, forward);
8301                                         VectorReflect(forward, 0, up, forward);
8302                                         VectorNormalize(forward);
8303                                         CrossProduct(up, forward, newright);
8304                                         VectorNormalize(newright);
8305                                         // rotate the quad around the up axis vector, this is made
8306                                         // especially easy by the fact we know the quad is flat,
8307                                         // so we only have to subtract the center position and
8308                                         // measure distance along the right vector, and then
8309                                         // multiply that by the newright vector and add back the
8310                                         // center position
8311                                         // we also need to subtract the old position to undo the
8312                                         // displacement from the center, which we do with a
8313                                         // DotProduct, the subtraction/addition of center is also
8314                                         // optimized into DotProducts here
8315                                         l = DotProduct(right, center);
8316                                         for (i = 0;i < 4;i++)
8317                                         {
8318                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8319                                                 f = DotProduct(right, v1) - l;
8320                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8321                                         }
8322                                 }
8323                         }
8324                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8325                         {
8326 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8327 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8328 //                              rsurface.batchnormal3f_bufferoffset = 0;
8329                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8330                         }
8331                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8332                         {
8333 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8334 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8335 //                              rsurface.batchsvector3f_bufferoffset = 0;
8336 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8337 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8338 //                              rsurface.batchtvector3f_bufferoffset = 0;
8339                                 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);
8340                         }
8341                         break;
8342                 case Q3DEFORM_NORMAL:
8343                         // deform the normals to make reflections wavey
8344                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8345                         rsurface.batchnormal3f_vertexbuffer = NULL;
8346                         rsurface.batchnormal3f_bufferoffset = 0;
8347                         for (j = 0;j < batchnumvertices;j++)
8348                         {
8349                                 float vertex[3];
8350                                 float *normal = rsurface.batchnormal3f + 3*j;
8351                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8352                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8353                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8354                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8355                                 VectorNormalize(normal);
8356                         }
8357                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8358                         {
8359 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8360 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8361 //                              rsurface.batchsvector3f_bufferoffset = 0;
8362 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8363 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8364 //                              rsurface.batchtvector3f_bufferoffset = 0;
8365                                 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);
8366                         }
8367                         break;
8368                 case Q3DEFORM_WAVE:
8369                         // deform vertex array to make wavey water and flags and such
8370                         waveparms[0] = deform->waveparms[0];
8371                         waveparms[1] = deform->waveparms[1];
8372                         waveparms[2] = deform->waveparms[2];
8373                         waveparms[3] = deform->waveparms[3];
8374                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8375                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8376                         // this is how a divisor of vertex influence on deformation
8377                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8378                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8379 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8380 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8381 //                      rsurface.batchvertex3f_bufferoffset = 0;
8382 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8383 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8384 //                      rsurface.batchnormal3f_bufferoffset = 0;
8385                         for (j = 0;j < batchnumvertices;j++)
8386                         {
8387                                 // if the wavefunc depends on time, evaluate it per-vertex
8388                                 if (waveparms[3])
8389                                 {
8390                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8391                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8392                                 }
8393                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8394                         }
8395                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8396                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8397                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8398                         {
8399 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8400 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8401 //                              rsurface.batchsvector3f_bufferoffset = 0;
8402 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8403 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8404 //                              rsurface.batchtvector3f_bufferoffset = 0;
8405                                 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);
8406                         }
8407                         break;
8408                 case Q3DEFORM_BULGE:
8409                         // deform vertex array to make the surface have moving bulges
8410 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8411 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8412 //                      rsurface.batchvertex3f_bufferoffset = 0;
8413 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8414 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8415 //                      rsurface.batchnormal3f_bufferoffset = 0;
8416                         for (j = 0;j < batchnumvertices;j++)
8417                         {
8418                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8419                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8420                         }
8421                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8422                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8423                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8424                         {
8425 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8426 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8427 //                              rsurface.batchsvector3f_bufferoffset = 0;
8428 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8429 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8430 //                              rsurface.batchtvector3f_bufferoffset = 0;
8431                                 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);
8432                         }
8433                         break;
8434                 case Q3DEFORM_MOVE:
8435                         // deform vertex array
8436                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8437                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8438                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8439                         VectorScale(deform->parms, scale, waveparms);
8440 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8441 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8442 //                      rsurface.batchvertex3f_bufferoffset = 0;
8443                         for (j = 0;j < batchnumvertices;j++)
8444                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8445                         break;
8446                 }
8447         }
8448
8449         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8450         {
8451         // generate texcoords based on the chosen texcoord source
8452                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8453                 {
8454                 default:
8455                 case Q3TCGEN_TEXTURE:
8456                         break;
8457                 case Q3TCGEN_LIGHTMAP:
8458         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8459         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8460         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8461                         if (rsurface.batchtexcoordlightmap2f)
8462                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8463                         break;
8464                 case Q3TCGEN_VECTOR:
8465         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8466         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8467         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8468                         for (j = 0;j < batchnumvertices;j++)
8469                         {
8470                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8471                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8472                         }
8473                         break;
8474                 case Q3TCGEN_ENVIRONMENT:
8475                         // make environment reflections using a spheremap
8476                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8477                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8478                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8479                         for (j = 0;j < batchnumvertices;j++)
8480                         {
8481                                 // identical to Q3A's method, but executed in worldspace so
8482                                 // carried models can be shiny too
8483
8484                                 float viewer[3], d, reflected[3], worldreflected[3];
8485
8486                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8487                                 // VectorNormalize(viewer);
8488
8489                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8490
8491                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8492                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8493                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8494                                 // note: this is proportinal to viewer, so we can normalize later
8495
8496                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8497                                 VectorNormalize(worldreflected);
8498
8499                                 // note: this sphere map only uses world x and z!
8500                                 // so positive and negative y will LOOK THE SAME.
8501                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8502                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8503                         }
8504                         break;
8505                 }
8506                 // the only tcmod that needs software vertex processing is turbulent, so
8507                 // check for it here and apply the changes if needed
8508                 // and we only support that as the first one
8509                 // (handling a mixture of turbulent and other tcmods would be problematic
8510                 //  without punting it entirely to a software path)
8511                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8512                 {
8513                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8514                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8515         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8516         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8517         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8518                         for (j = 0;j < batchnumvertices;j++)
8519                         {
8520                                 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);
8521                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8522                         }
8523                 }
8524         }
8525 }
8526
8527 void RSurf_DrawBatch(void)
8528 {
8529         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8530         // through the pipeline, killing it earlier in the pipeline would have
8531         // per-surface overhead rather than per-batch overhead, so it's best to
8532         // reject it here, before it hits glDraw.
8533         if (rsurface.batchnumtriangles == 0)
8534                 return;
8535 #if 0
8536         // batch debugging code
8537         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8538         {
8539                 int i;
8540                 int j;
8541                 int c;
8542                 const int *e;
8543                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8544                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8545                 {
8546                         c = e[i];
8547                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8548                         {
8549                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8550                                 {
8551                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8552                                                 Sys_Abort("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);
8553                                         break;
8554                                 }
8555                         }
8556                 }
8557         }
8558 #endif
8559         if (rsurface.batchmultidraw)
8560         {
8561                 // issue multiple draws rather than copying index data
8562                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8563                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8564                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8565                 for (i = 0;i < numsurfaces;)
8566                 {
8567                         // combine consecutive surfaces as one draw
8568                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8569                                 if (surfacelist[j] != surfacelist[k] + 1)
8570                                         break;
8571                         firstvertex = surfacelist[i]->num_firstvertex;
8572                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8573                         firsttriangle = surfacelist[i]->num_firsttriangle;
8574                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8575                         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);
8576                         i = j;
8577                 }
8578         }
8579         else
8580         {
8581                 // there is only one consecutive run of index data (may have been combined)
8582                 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);
8583         }
8584 }
8585
8586 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8587 {
8588         // pick the closest matching water plane
8589         int planeindex, vertexindex, bestplaneindex = -1;
8590         float d, bestd;
8591         vec3_t vert;
8592         const float *v;
8593         r_waterstate_waterplane_t *p;
8594         qbool prepared = false;
8595         bestd = 0;
8596         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8597         {
8598                 if(p->camera_entity != rsurface.texture->camera_entity)
8599                         continue;
8600                 d = 0;
8601                 if(!prepared)
8602                 {
8603                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8604                         prepared = true;
8605                         if(rsurface.batchnumvertices == 0)
8606                                 break;
8607                 }
8608                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8609                 {
8610                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8611                         d += fabs(PlaneDiff(vert, &p->plane));
8612                 }
8613                 if (bestd > d || bestplaneindex < 0)
8614                 {
8615                         bestd = d;
8616                         bestplaneindex = planeindex;
8617                 }
8618         }
8619         return bestplaneindex;
8620         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8621         // this situation though, as it might be better to render single larger
8622         // batches with useless stuff (backface culled for example) than to
8623         // render multiple smaller batches
8624 }
8625
8626 void RSurf_SetupDepthAndCulling(bool ui)
8627 {
8628         // submodels are biased to avoid z-fighting with world surfaces that they
8629         // may be exactly overlapping (avoids z-fighting artifacts on certain
8630         // doors and things in Quake maps)
8631         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8632         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8633         GL_DepthTest(!ui && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8634         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8635 }
8636
8637 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8638 {
8639         int j;
8640         const float *v;
8641         float p[3], mins[3], maxs[3];
8642         int scissor[4];
8643         // transparent sky would be ridiculous
8644         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8645                 return;
8646         R_SetupShader_Generic_NoTexture(false, false);
8647         skyrenderlater = true;
8648         RSurf_SetupDepthAndCulling(false);
8649         GL_DepthMask(true);
8650
8651         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8652         if (r_sky_scissor.integer)
8653         {
8654                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8655                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8656                 {
8657                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8658                         if (j > 0)
8659                         {
8660                                 if (mins[0] > p[0]) mins[0] = p[0];
8661                                 if (mins[1] > p[1]) mins[1] = p[1];
8662                                 if (mins[2] > p[2]) mins[2] = p[2];
8663                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8664                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8665                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8666                         }
8667                         else
8668                         {
8669                                 VectorCopy(p, mins);
8670                                 VectorCopy(p, maxs);
8671                         }
8672                 }
8673                 if (!R_ScissorForBBox(mins, maxs, scissor))
8674                 {
8675                         if (skyscissor[2])
8676                         {
8677                                 if (skyscissor[0] > scissor[0])
8678                                 {
8679                                         skyscissor[2] += skyscissor[0] - scissor[0];
8680                                         skyscissor[0] = scissor[0];
8681                                 }
8682                                 if (skyscissor[1] > scissor[1])
8683                                 {
8684                                         skyscissor[3] += skyscissor[1] - scissor[1];
8685                                         skyscissor[1] = scissor[1];
8686                                 }
8687                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8688                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8689                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8690                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8691                         }
8692                         else
8693                                 Vector4Copy(scissor, skyscissor);
8694                 }
8695         }
8696
8697         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8698         // skymasking on them, and Quake3 never did sky masking (unlike
8699         // software Quake and software Quake2), so disable the sky masking
8700         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8701         // and skymasking also looks very bad when noclipping outside the
8702         // level, so don't use it then either.
8703         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)
8704         {
8705                 R_Mesh_ResetTextureState();
8706                 if (skyrendermasked)
8707                 {
8708                         R_SetupShader_DepthOrShadow(false, false, false);
8709                         // depth-only (masking)
8710                         GL_ColorMask(0, 0, 0, 0);
8711                         // just to make sure that braindead drivers don't draw
8712                         // anything despite that colormask...
8713                         GL_BlendFunc(GL_ZERO, GL_ONE);
8714                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8715                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8716                 }
8717                 else
8718                 {
8719                         R_SetupShader_Generic_NoTexture(false, false);
8720                         // fog sky
8721                         GL_BlendFunc(GL_ONE, GL_ZERO);
8722                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8723                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8724                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8725                 }
8726                 RSurf_DrawBatch();
8727                 if (skyrendermasked)
8728                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8729         }
8730         R_Mesh_ResetTextureState();
8731         GL_Color(1, 1, 1, 1);
8732 }
8733
8734 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8735 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8736 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8737 {
8738         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8739                 return;
8740         if (prepass)
8741         {
8742                 // render screenspace normalmap to texture
8743                 GL_DepthMask(true);
8744                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8745                 RSurf_DrawBatch();
8746                 return;
8747         }
8748
8749         // bind lightmap texture
8750
8751         // water/refraction/reflection/camera surfaces have to be handled specially
8752         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8753         {
8754                 int start, end, startplaneindex;
8755                 for (start = 0;start < texturenumsurfaces;start = end)
8756                 {
8757                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8758                         if(startplaneindex < 0)
8759                         {
8760                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8761                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8762                                 end = start + 1;
8763                                 continue;
8764                         }
8765                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8766                                 ;
8767                         // now that we have a batch using the same planeindex, render it
8768                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8769                         {
8770                                 // render water or distortion background
8771                                 GL_DepthMask(true);
8772                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8773                                 RSurf_DrawBatch();
8774                                 // blend surface on top
8775                                 GL_DepthMask(false);
8776                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8777                                 RSurf_DrawBatch();
8778                         }
8779                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8780                         {
8781                                 // render surface with reflection texture as input
8782                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8783                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8784                                 RSurf_DrawBatch();
8785                         }
8786                 }
8787                 return;
8788         }
8789
8790         // render surface batch normally
8791         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8792         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8793         RSurf_DrawBatch();
8794 }
8795
8796 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8797 {
8798         int vi;
8799         int j;
8800         int texturesurfaceindex;
8801         int k;
8802         const msurface_t *surface;
8803         float surfacecolor4f[4];
8804         float c[4];
8805         texture_t *t = rsurface.texture;
8806
8807 //      R_Mesh_ResetTextureState();
8808         R_SetupShader_Generic_NoTexture(false, false);
8809
8810         GL_BlendFunc(GL_ONE, GL_ZERO);
8811         GL_DepthMask(writedepth);
8812
8813         switch (r_showsurfaces.integer)
8814         {
8815                 case 1:
8816                 default:
8817                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8818                         vi = 0;
8819                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8820                         {
8821                                 surface = texturesurfacelist[texturesurfaceindex];
8822                                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8823                                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8824                                 for (j = 0;j < surface->num_vertices;j++)
8825                                 {
8826                                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8827                                         vi++;
8828                                 }
8829                         }
8830                         break;
8831                 case 3:
8832                         if(t && t->currentskinframe)
8833                         {
8834                                 Vector4Copy(t->currentskinframe->avgcolor, c);
8835                                 c[3] *= t->currentalpha;
8836                         }
8837                         else
8838                         {
8839                                 Vector4Set(c, 1, 0, 1, 1);
8840                         }
8841                         if (t && (t->pantstexture || t->shirttexture))
8842                         {
8843                                 VectorMAM(0.7, t->render_colormap_pants, 0.3, t->render_colormap_shirt, c);
8844                         }
8845                         VectorScale(c, 2 * r_refdef.view.colorscale, c);
8846                         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
8847                                 c[3] *= r_wateralpha.value;
8848                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8849                         vi = 0;
8850                         if (rsurface.modellightmapcolor4f)
8851                         {
8852                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8853                                 {
8854                                         surface = texturesurfacelist[texturesurfaceindex];
8855                                         for (j = 0;j < surface->num_vertices;j++)
8856                                         {
8857                                                 float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
8858                                                 Vector4Multiply(ptr, c, ptr);
8859                                                 vi++;
8860                                         }
8861                                 }
8862                         }
8863                         else
8864                         {
8865                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8866                                 {
8867                                         surface = texturesurfacelist[texturesurfaceindex];
8868                                         for (j = 0;j < surface->num_vertices;j++)
8869                                         {
8870                                                 float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
8871                                                 Vector4Copy(c, ptr);
8872                                                 vi++;
8873                                         }
8874                                 }
8875                         }
8876                         break;
8877         }
8878         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8879         RSurf_DrawBatch();
8880 }
8881
8882 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8883 {
8884         CHECKGLERROR
8885         RSurf_SetupDepthAndCulling(ui);
8886         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8887         {
8888                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8889                 return;
8890         }
8891         switch (vid.renderpath)
8892         {
8893         case RENDERPATH_GL32:
8894         case RENDERPATH_GLES2:
8895                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8896                 break;
8897         }
8898         CHECKGLERROR
8899 }
8900
8901 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8902 {
8903         int i, j;
8904         int texturenumsurfaces, endsurface;
8905         texture_t *texture;
8906         const msurface_t *surface;
8907         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8908
8909         RSurf_ActiveModelEntity(ent, true, true, false);
8910
8911         if (r_transparentdepthmasking.integer)
8912         {
8913                 qbool setup = false;
8914                 for (i = 0;i < numsurfaces;i = j)
8915                 {
8916                         j = i + 1;
8917                         surface = rsurface.modelsurfaces + surfacelist[i];
8918                         texture = surface->texture;
8919                         rsurface.texture = R_GetCurrentTexture(texture);
8920                         rsurface.lightmaptexture = NULL;
8921                         rsurface.deluxemaptexture = NULL;
8922                         rsurface.uselightmaptexture = false;
8923                         // scan ahead until we find a different texture
8924                         endsurface = min(i + 1024, numsurfaces);
8925                         texturenumsurfaces = 0;
8926                         texturesurfacelist[texturenumsurfaces++] = surface;
8927                         for (;j < endsurface;j++)
8928                         {
8929                                 surface = rsurface.modelsurfaces + surfacelist[j];
8930                                 if (texture != surface->texture)
8931                                         break;
8932                                 texturesurfacelist[texturenumsurfaces++] = surface;
8933                         }
8934                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8935                                 continue;
8936                         // render the range of surfaces as depth
8937                         if (!setup)
8938                         {
8939                                 setup = true;
8940                                 GL_ColorMask(0,0,0,0);
8941                                 GL_Color(1,1,1,1);
8942                                 GL_DepthTest(true);
8943                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8944                                 GL_DepthMask(true);
8945 //                              R_Mesh_ResetTextureState();
8946                         }
8947                         RSurf_SetupDepthAndCulling(false);
8948                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8949                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8950                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8951                         RSurf_DrawBatch();
8952                 }
8953                 if (setup)
8954                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8955         }
8956
8957         for (i = 0;i < numsurfaces;i = j)
8958         {
8959                 j = i + 1;
8960                 surface = rsurface.modelsurfaces + surfacelist[i];
8961                 texture = surface->texture;
8962                 rsurface.texture = R_GetCurrentTexture(texture);
8963                 // scan ahead until we find a different texture
8964                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8965                 texturenumsurfaces = 0;
8966                 texturesurfacelist[texturenumsurfaces++] = surface;
8967                         rsurface.lightmaptexture = surface->lightmaptexture;
8968                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8969                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8970                         for (;j < endsurface;j++)
8971                         {
8972                                 surface = rsurface.modelsurfaces + surfacelist[j];
8973                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8974                                         break;
8975                                 texturesurfacelist[texturenumsurfaces++] = surface;
8976                         }
8977                 // render the range of surfaces
8978                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8979         }
8980         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8981 }
8982
8983 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8984 {
8985         // transparent surfaces get pushed off into the transparent queue
8986         int surfacelistindex;
8987         const msurface_t *surface;
8988         vec3_t tempcenter, center;
8989         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8990         {
8991                 surface = texturesurfacelist[surfacelistindex];
8992                 if (r_transparent_sortsurfacesbynearest.integer)
8993                 {
8994                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8995                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8996                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8997                 }
8998                 else
8999                 {
9000                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9001                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9002                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9003                 }
9004                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9005                 if (rsurface.entity->transparent_offset) // transparent offset
9006                 {
9007                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9008                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9009                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9010                 }
9011                 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);
9012         }
9013 }
9014
9015 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9016 {
9017         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9018                 return;
9019         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9020                 return;
9021         RSurf_SetupDepthAndCulling(false);
9022         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9023         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9024         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9025         RSurf_DrawBatch();
9026 }
9027
9028 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9029 {
9030         CHECKGLERROR
9031         if (ui)
9032                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9033         else if (depthonly)
9034                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9035         else if (prepass)
9036         {
9037                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9038                         return;
9039                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9040                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9041                 else
9042                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9043         }
9044         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9045                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9046         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9047                 return;
9048         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9049         {
9050                 // in the deferred case, transparent surfaces were queued during prepass
9051                 if (!r_shadow_usingdeferredprepass)
9052                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9053         }
9054         else
9055         {
9056                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9057                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9058         }
9059         CHECKGLERROR
9060 }
9061
9062 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9063 {
9064         int i, j;
9065         texture_t *texture;
9066         R_FrameData_SetMark();
9067         // break the surface list down into batches by texture and use of lightmapping
9068         for (i = 0;i < numsurfaces;i = j)
9069         {
9070                 j = i + 1;
9071                 // texture is the base texture pointer, rsurface.texture is the
9072                 // current frame/skin the texture is directing us to use (for example
9073                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9074                 // use skin 1 instead)
9075                 texture = surfacelist[i]->texture;
9076                 rsurface.texture = R_GetCurrentTexture(texture);
9077                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9078                 {
9079                         // if this texture is not the kind we want, skip ahead to the next one
9080                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9081                                 ;
9082                         continue;
9083                 }
9084                 if(depthonly || prepass)
9085                 {
9086                         rsurface.lightmaptexture = NULL;
9087                         rsurface.deluxemaptexture = NULL;
9088                         rsurface.uselightmaptexture = false;
9089                         // simply scan ahead until we find a different texture or lightmap state
9090                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9091                                 ;
9092                 }
9093                 else
9094                 {
9095                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9096                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9097                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9098                         // simply scan ahead until we find a different texture or lightmap state
9099                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9100                                 ;
9101                 }
9102                 // render the range of surfaces
9103                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9104         }
9105         R_FrameData_ReturnToMark();
9106 }
9107
9108 float locboxvertex3f[6*4*3] =
9109 {
9110         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9111         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9112         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9113         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9114         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9115         1,0,0, 0,0,0, 0,1,0, 1,1,0
9116 };
9117
9118 unsigned short locboxelements[6*2*3] =
9119 {
9120          0, 1, 2, 0, 2, 3,
9121          4, 5, 6, 4, 6, 7,
9122          8, 9,10, 8,10,11,
9123         12,13,14, 12,14,15,
9124         16,17,18, 16,18,19,
9125         20,21,22, 20,22,23
9126 };
9127
9128 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9129 {
9130         int i, j;
9131         cl_locnode_t *loc = (cl_locnode_t *)ent;
9132         vec3_t mins, size;
9133         float vertex3f[6*4*3];
9134         CHECKGLERROR
9135         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9136         GL_DepthMask(false);
9137         GL_DepthRange(0, 1);
9138         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9139         GL_DepthTest(true);
9140         GL_CullFace(GL_NONE);
9141         R_EntityMatrix(&identitymatrix);
9142
9143 //      R_Mesh_ResetTextureState();
9144
9145         i = surfacelist[0];
9146         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9147                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9148                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9149                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9150
9151         if (VectorCompare(loc->mins, loc->maxs))
9152         {
9153                 VectorSet(size, 2, 2, 2);
9154                 VectorMA(loc->mins, -0.5f, size, mins);
9155         }
9156         else
9157         {
9158                 VectorCopy(loc->mins, mins);
9159                 VectorSubtract(loc->maxs, loc->mins, size);
9160         }
9161
9162         for (i = 0;i < 6*4*3;)
9163                 for (j = 0;j < 3;j++, i++)
9164                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9165
9166         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9167         R_SetupShader_Generic_NoTexture(false, false);
9168         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9169 }
9170
9171 void R_DrawLocs(void)
9172 {
9173         int index;
9174         cl_locnode_t *loc, *nearestloc;
9175         vec3_t center;
9176         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9177         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9178         {
9179                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9180                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9181         }
9182 }
9183
9184 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9185 {
9186         if (decalsystem->decals)
9187                 Mem_Free(decalsystem->decals);
9188         memset(decalsystem, 0, sizeof(*decalsystem));
9189 }
9190
9191 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)
9192 {
9193         tridecal_t *decal;
9194         tridecal_t *decals;
9195         int i;
9196
9197         // expand or initialize the system
9198         if (decalsystem->maxdecals <= decalsystem->numdecals)
9199         {
9200                 decalsystem_t old = *decalsystem;
9201                 qbool useshortelements;
9202                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9203                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9204                 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)));
9205                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9206                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9207                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9208                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9209                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9210                 if (decalsystem->numdecals)
9211                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9212                 if (old.decals)
9213                         Mem_Free(old.decals);
9214                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9215                         decalsystem->element3i[i] = i;
9216                 if (useshortelements)
9217                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9218                                 decalsystem->element3s[i] = i;
9219         }
9220
9221         // grab a decal and search for another free slot for the next one
9222         decals = decalsystem->decals;
9223         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9224         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9225                 ;
9226         decalsystem->freedecal = i;
9227         if (decalsystem->numdecals <= i)
9228                 decalsystem->numdecals = i + 1;
9229
9230         // initialize the decal
9231         decal->lived = 0;
9232         decal->triangleindex = triangleindex;
9233         decal->surfaceindex = surfaceindex;
9234         decal->decalsequence = decalsequence;
9235         decal->color4f[0][0] = c0[0];
9236         decal->color4f[0][1] = c0[1];
9237         decal->color4f[0][2] = c0[2];
9238         decal->color4f[0][3] = 1;
9239         decal->color4f[1][0] = c1[0];
9240         decal->color4f[1][1] = c1[1];
9241         decal->color4f[1][2] = c1[2];
9242         decal->color4f[1][3] = 1;
9243         decal->color4f[2][0] = c2[0];
9244         decal->color4f[2][1] = c2[1];
9245         decal->color4f[2][2] = c2[2];
9246         decal->color4f[2][3] = 1;
9247         decal->vertex3f[0][0] = v0[0];
9248         decal->vertex3f[0][1] = v0[1];
9249         decal->vertex3f[0][2] = v0[2];
9250         decal->vertex3f[1][0] = v1[0];
9251         decal->vertex3f[1][1] = v1[1];
9252         decal->vertex3f[1][2] = v1[2];
9253         decal->vertex3f[2][0] = v2[0];
9254         decal->vertex3f[2][1] = v2[1];
9255         decal->vertex3f[2][2] = v2[2];
9256         decal->texcoord2f[0][0] = t0[0];
9257         decal->texcoord2f[0][1] = t0[1];
9258         decal->texcoord2f[1][0] = t1[0];
9259         decal->texcoord2f[1][1] = t1[1];
9260         decal->texcoord2f[2][0] = t2[0];
9261         decal->texcoord2f[2][1] = t2[1];
9262         TriangleNormal(v0, v1, v2, decal->plane);
9263         VectorNormalize(decal->plane);
9264         decal->plane[3] = DotProduct(v0, decal->plane);
9265 }
9266
9267 extern cvar_t cl_decals_bias;
9268 extern cvar_t cl_decals_models;
9269 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9270 // baseparms, parms, temps
9271 static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qbool dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9272 {
9273         int cornerindex;
9274         int index;
9275         float v[9][3];
9276         const float *vertex3f;
9277         const float *normal3f;
9278         int numpoints;
9279         float points[2][9][3];
9280         float temp[3];
9281         float tc[9][2];
9282         float f;
9283         float c[9][4];
9284         const int *e;
9285
9286         e = rsurface.modelelement3i + 3*triangleindex;
9287
9288         vertex3f = rsurface.modelvertex3f;
9289         normal3f = rsurface.modelnormal3f;
9290
9291         if (normal3f)
9292         {
9293                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9294                 {
9295                         index = 3*e[cornerindex];
9296                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9297                 }
9298         }
9299         else
9300         {
9301                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9302                 {
9303                         index = 3*e[cornerindex];
9304                         VectorCopy(vertex3f + index, v[cornerindex]);
9305                 }
9306         }
9307
9308         // cull backfaces
9309         //TriangleNormal(v[0], v[1], v[2], normal);
9310         //if (DotProduct(normal, localnormal) < 0.0f)
9311         //      continue;
9312         // clip by each of the box planes formed from the projection matrix
9313         // if anything survives, we emit the decal
9314         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]);
9315         if (numpoints < 3)
9316                 return;
9317         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]);
9318         if (numpoints < 3)
9319                 return;
9320         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]);
9321         if (numpoints < 3)
9322                 return;
9323         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]);
9324         if (numpoints < 3)
9325                 return;
9326         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]);
9327         if (numpoints < 3)
9328                 return;
9329         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]);
9330         if (numpoints < 3)
9331                 return;
9332         // some part of the triangle survived, so we have to accept it...
9333         if (dynamic)
9334         {
9335                 // dynamic always uses the original triangle
9336                 numpoints = 3;
9337                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9338                 {
9339                         index = 3*e[cornerindex];
9340                         VectorCopy(vertex3f + index, v[cornerindex]);
9341                 }
9342         }
9343         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9344         {
9345                 // convert vertex positions to texcoords
9346                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9347                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9348                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9349                 // calculate distance fade from the projection origin
9350                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9351                 f = bound(0.0f, f, 1.0f);
9352                 c[cornerindex][0] = r * f;
9353                 c[cornerindex][1] = g * f;
9354                 c[cornerindex][2] = b * f;
9355                 c[cornerindex][3] = 1.0f;
9356                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9357         }
9358         if (dynamic)
9359                 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);
9360         else
9361                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9362                         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);
9363 }
9364 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)
9365 {
9366         matrix4x4_t projection;
9367         decalsystem_t *decalsystem;
9368         qbool dynamic;
9369         model_t *model;
9370         const msurface_t *surface;
9371         const msurface_t *surfaces;
9372         const texture_t *texture;
9373         int numtriangles;
9374         int surfaceindex;
9375         int triangleindex;
9376         float localorigin[3];
9377         float localnormal[3];
9378         float localmins[3];
9379         float localmaxs[3];
9380         float localsize;
9381         //float normal[3];
9382         float planes[6][4];
9383         float angles[3];
9384         bih_t *bih;
9385         int bih_triangles_count;
9386         int bih_triangles[256];
9387         int bih_surfaces[256];
9388
9389         decalsystem = &ent->decalsystem;
9390         model = ent->model;
9391         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9392         {
9393                 R_DecalSystem_Reset(&ent->decalsystem);
9394                 return;
9395         }
9396
9397         if (!model->brush.data_leafs && !cl_decals_models.integer)
9398         {
9399                 if (decalsystem->model)
9400                         R_DecalSystem_Reset(decalsystem);
9401                 return;
9402         }
9403
9404         if (decalsystem->model != model)
9405                 R_DecalSystem_Reset(decalsystem);
9406         decalsystem->model = model;
9407
9408         RSurf_ActiveModelEntity(ent, true, false, false);
9409
9410         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9411         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9412         VectorNormalize(localnormal);
9413         localsize = worldsize*rsurface.inversematrixscale;
9414         localmins[0] = localorigin[0] - localsize;
9415         localmins[1] = localorigin[1] - localsize;
9416         localmins[2] = localorigin[2] - localsize;
9417         localmaxs[0] = localorigin[0] + localsize;
9418         localmaxs[1] = localorigin[1] + localsize;
9419         localmaxs[2] = localorigin[2] + localsize;
9420
9421         //VectorCopy(localnormal, planes[4]);
9422         //VectorVectors(planes[4], planes[2], planes[0]);
9423         AnglesFromVectors(angles, localnormal, NULL, false);
9424         AngleVectors(angles, planes[0], planes[2], planes[4]);
9425         VectorNegate(planes[0], planes[1]);
9426         VectorNegate(planes[2], planes[3]);
9427         VectorNegate(planes[4], planes[5]);
9428         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9429         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9430         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9431         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9432         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9433         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9434
9435 #if 1
9436 // works
9437 {
9438         matrix4x4_t forwardprojection;
9439         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9440         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9441 }
9442 #else
9443 // broken
9444 {
9445         float projectionvector[4][3];
9446         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9447         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9448         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9449         projectionvector[0][0] = planes[0][0] * ilocalsize;
9450         projectionvector[0][1] = planes[1][0] * ilocalsize;
9451         projectionvector[0][2] = planes[2][0] * ilocalsize;
9452         projectionvector[1][0] = planes[0][1] * ilocalsize;
9453         projectionvector[1][1] = planes[1][1] * ilocalsize;
9454         projectionvector[1][2] = planes[2][1] * ilocalsize;
9455         projectionvector[2][0] = planes[0][2] * ilocalsize;
9456         projectionvector[2][1] = planes[1][2] * ilocalsize;
9457         projectionvector[2][2] = planes[2][2] * ilocalsize;
9458         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9459         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9460         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9461         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9462 }
9463 #endif
9464
9465         dynamic = model->surfmesh.isanimated;
9466         surfaces = model->data_surfaces;
9467
9468         bih = NULL;
9469         bih_triangles_count = -1;
9470         if(!dynamic)
9471         {
9472                 if(model->render_bih.numleafs)
9473                         bih = &model->render_bih;
9474                 else if(model->collision_bih.numleafs)
9475                         bih = &model->collision_bih;
9476         }
9477         if(bih)
9478                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9479         if(bih_triangles_count == 0)
9480                 return;
9481         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9482                 return;
9483         if(bih_triangles_count > 0)
9484         {
9485                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9486                 {
9487                         surfaceindex = bih_surfaces[triangleindex];
9488                         surface = surfaces + surfaceindex;
9489                         texture = surface->texture;
9490                         if (!texture)
9491                                 continue;
9492                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9493                                 continue;
9494                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9495                                 continue;
9496                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9497                 }
9498         }
9499         else
9500         {
9501                 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
9502                 {
9503                         surface = surfaces + surfaceindex;
9504                         // check cull box first because it rejects more than any other check
9505                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9506                                 continue;
9507                         // skip transparent surfaces
9508                         texture = surface->texture;
9509                         if (!texture)
9510                                 continue;
9511                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9512                                 continue;
9513                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9514                                 continue;
9515                         numtriangles = surface->num_triangles;
9516                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9517                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9518                 }
9519         }
9520 }
9521
9522 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9523 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)
9524 {
9525         int renderentityindex;
9526         float worldmins[3];
9527         float worldmaxs[3];
9528         entity_render_t *ent;
9529
9530         worldmins[0] = worldorigin[0] - worldsize;
9531         worldmins[1] = worldorigin[1] - worldsize;
9532         worldmins[2] = worldorigin[2] - worldsize;
9533         worldmaxs[0] = worldorigin[0] + worldsize;
9534         worldmaxs[1] = worldorigin[1] + worldsize;
9535         worldmaxs[2] = worldorigin[2] + worldsize;
9536
9537         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9538
9539         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9540         {
9541                 ent = r_refdef.scene.entities[renderentityindex];
9542                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9543                         continue;
9544
9545                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9546         }
9547 }
9548
9549 typedef struct r_decalsystem_splatqueue_s
9550 {
9551         vec3_t worldorigin;
9552         vec3_t worldnormal;
9553         float color[4];
9554         float tcrange[4];
9555         float worldsize;
9556         unsigned int decalsequence;
9557 }
9558 r_decalsystem_splatqueue_t;
9559
9560 int r_decalsystem_numqueued = 0;
9561 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9562
9563 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)
9564 {
9565         r_decalsystem_splatqueue_t *queue;
9566
9567         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9568                 return;
9569
9570         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9571         VectorCopy(worldorigin, queue->worldorigin);
9572         VectorCopy(worldnormal, queue->worldnormal);
9573         Vector4Set(queue->color, r, g, b, a);
9574         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9575         queue->worldsize = worldsize;
9576         queue->decalsequence = cl.decalsequence++;
9577 }
9578
9579 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9580 {
9581         int i;
9582         r_decalsystem_splatqueue_t *queue;
9583
9584         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9585                 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);
9586         r_decalsystem_numqueued = 0;
9587 }
9588
9589 extern cvar_t cl_decals_max;
9590 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9591 {
9592         int i;
9593         decalsystem_t *decalsystem = &ent->decalsystem;
9594         int numdecals;
9595         unsigned int killsequence;
9596         tridecal_t *decal;
9597         float frametime;
9598         float lifetime;
9599
9600         if (!decalsystem->numdecals)
9601                 return;
9602
9603         if (r_showsurfaces.integer)
9604                 return;
9605
9606         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9607         {
9608                 R_DecalSystem_Reset(decalsystem);
9609                 return;
9610         }
9611
9612         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9613         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9614
9615         if (decalsystem->lastupdatetime)
9616                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9617         else
9618                 frametime = 0;
9619         decalsystem->lastupdatetime = r_refdef.scene.time;
9620         numdecals = decalsystem->numdecals;
9621
9622         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9623         {
9624                 if (decal->color4f[0][3])
9625                 {
9626                         decal->lived += frametime;
9627                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9628                         {
9629                                 memset(decal, 0, sizeof(*decal));
9630                                 if (decalsystem->freedecal > i)
9631                                         decalsystem->freedecal = i;
9632                         }
9633                 }
9634         }
9635         decal = decalsystem->decals;
9636         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9637                 numdecals--;
9638
9639         // collapse the array by shuffling the tail decals into the gaps
9640         for (;;)
9641         {
9642                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9643                         decalsystem->freedecal++;
9644                 if (decalsystem->freedecal == numdecals)
9645                         break;
9646                 decal[decalsystem->freedecal] = decal[--numdecals];
9647         }
9648
9649         decalsystem->numdecals = numdecals;
9650
9651         if (numdecals <= 0)
9652         {
9653                 // if there are no decals left, reset decalsystem
9654                 R_DecalSystem_Reset(decalsystem);
9655         }
9656 }
9657
9658 extern skinframe_t *decalskinframe;
9659 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9660 {
9661         int i;
9662         decalsystem_t *decalsystem = &ent->decalsystem;
9663         int numdecals;
9664         tridecal_t *decal;
9665         float faderate;
9666         float alpha;
9667         float *v3f;
9668         float *c4f;
9669         float *t2f;
9670         const int *e;
9671         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9672         int numtris = 0;
9673
9674         numdecals = decalsystem->numdecals;
9675         if (!numdecals)
9676                 return;
9677
9678         if (r_showsurfaces.integer)
9679                 return;
9680
9681         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9682         {
9683                 R_DecalSystem_Reset(decalsystem);
9684                 return;
9685         }
9686
9687         // if the model is static it doesn't matter what value we give for
9688         // wantnormals and wanttangents, so this logic uses only rules applicable
9689         // to a model, knowing that they are meaningless otherwise
9690         RSurf_ActiveModelEntity(ent, false, false, false);
9691
9692         decalsystem->lastupdatetime = r_refdef.scene.time;
9693
9694         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9695
9696         // update vertex positions for animated models
9697         v3f = decalsystem->vertex3f;
9698         c4f = decalsystem->color4f;
9699         t2f = decalsystem->texcoord2f;
9700         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9701         {
9702                 if (!decal->color4f[0][3])
9703                         continue;
9704
9705                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9706                         continue;
9707
9708                 // skip backfaces
9709                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9710                         continue;
9711
9712                 // update color values for fading decals
9713                 if (decal->lived >= cl_decals_time.value)
9714                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9715                 else
9716                         alpha = 1.0f;
9717
9718                 c4f[ 0] = decal->color4f[0][0] * alpha;
9719                 c4f[ 1] = decal->color4f[0][1] * alpha;
9720                 c4f[ 2] = decal->color4f[0][2] * alpha;
9721                 c4f[ 3] = 1;
9722                 c4f[ 4] = decal->color4f[1][0] * alpha;
9723                 c4f[ 5] = decal->color4f[1][1] * alpha;
9724                 c4f[ 6] = decal->color4f[1][2] * alpha;
9725                 c4f[ 7] = 1;
9726                 c4f[ 8] = decal->color4f[2][0] * alpha;
9727                 c4f[ 9] = decal->color4f[2][1] * alpha;
9728                 c4f[10] = decal->color4f[2][2] * alpha;
9729                 c4f[11] = 1;
9730
9731                 t2f[0] = decal->texcoord2f[0][0];
9732                 t2f[1] = decal->texcoord2f[0][1];
9733                 t2f[2] = decal->texcoord2f[1][0];
9734                 t2f[3] = decal->texcoord2f[1][1];
9735                 t2f[4] = decal->texcoord2f[2][0];
9736                 t2f[5] = decal->texcoord2f[2][1];
9737
9738                 // update vertex positions for animated models
9739                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9740                 {
9741                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9742                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9743                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9744                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9745                 }
9746                 else
9747                 {
9748                         VectorCopy(decal->vertex3f[0], v3f);
9749                         VectorCopy(decal->vertex3f[1], v3f + 3);
9750                         VectorCopy(decal->vertex3f[2], v3f + 6);
9751                 }
9752
9753                 if (r_refdef.fogenabled)
9754                 {
9755                         alpha = RSurf_FogVertex(v3f);
9756                         VectorScale(c4f, alpha, c4f);
9757                         alpha = RSurf_FogVertex(v3f + 3);
9758                         VectorScale(c4f + 4, alpha, c4f + 4);
9759                         alpha = RSurf_FogVertex(v3f + 6);
9760                         VectorScale(c4f + 8, alpha, c4f + 8);
9761                 }
9762
9763                 v3f += 9;
9764                 c4f += 12;
9765                 t2f += 6;
9766                 numtris++;
9767         }
9768
9769         if (numtris > 0)
9770         {
9771                 r_refdef.stats[r_stat_drawndecals] += numtris;
9772
9773                 // now render the decals all at once
9774                 // (this assumes they all use one particle font texture!)
9775                 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);
9776 //              R_Mesh_ResetTextureState();
9777                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9778                 GL_DepthMask(false);
9779                 GL_DepthRange(0, 1);
9780                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9781                 GL_DepthTest(true);
9782                 GL_CullFace(GL_NONE);
9783                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9784                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9785                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9786         }
9787 }
9788
9789 static void R_DrawModelDecals(void)
9790 {
9791         int i, numdecals;
9792
9793         // fade faster when there are too many decals
9794         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9795         for (i = 0;i < r_refdef.scene.numentities;i++)
9796                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9797
9798         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9799         for (i = 0;i < r_refdef.scene.numentities;i++)
9800                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9801                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9802
9803         R_DecalSystem_ApplySplatEntitiesQueue();
9804
9805         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9806         for (i = 0;i < r_refdef.scene.numentities;i++)
9807                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9808
9809         r_refdef.stats[r_stat_totaldecals] += numdecals;
9810
9811         if (r_showsurfaces.integer || !r_drawdecals.integer)
9812                 return;
9813
9814         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9815
9816         for (i = 0;i < r_refdef.scene.numentities;i++)
9817         {
9818                 if (!r_refdef.viewcache.entityvisible[i])
9819                         continue;
9820                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9821                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9822         }
9823 }
9824
9825 static void R_DrawDebugModel(void)
9826 {
9827         entity_render_t *ent = rsurface.entity;
9828         int j, flagsmask;
9829         const msurface_t *surface;
9830         model_t *model = ent->model;
9831
9832         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9833                 return;
9834
9835         if (r_showoverdraw.value > 0)
9836         {
9837                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9838                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9839                 R_SetupShader_Generic_NoTexture(false, false);
9840                 GL_DepthTest(false);
9841                 GL_DepthMask(false);
9842                 GL_DepthRange(0, 1);
9843                 GL_BlendFunc(GL_ONE, GL_ONE);
9844                 for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
9845                 {
9846                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9847                                 continue;
9848                         surface = model->data_surfaces + j;
9849                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9850                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9851                         {
9852                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9853                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9854                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9855                                         GL_Color(c, 0, 0, 1.0f);
9856                                 else if (ent == r_refdef.scene.worldentity)
9857                                         GL_Color(c, c, c, 1.0f);
9858                                 else
9859                                         GL_Color(0, c, 0, 1.0f);
9860                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9861                                 RSurf_DrawBatch();
9862                         }
9863                 }
9864                 rsurface.texture = NULL;
9865         }
9866
9867         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9868
9869 //      R_Mesh_ResetTextureState();
9870         R_SetupShader_Generic_NoTexture(false, false);
9871         GL_DepthRange(0, 1);
9872         GL_DepthTest(!r_showdisabledepthtest.integer);
9873         GL_DepthMask(false);
9874         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9875
9876         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9877         {
9878                 int triangleindex;
9879                 int bihleafindex;
9880                 qbool cullbox = false;
9881                 const q3mbrush_t *brush;
9882                 const bih_t *bih = &model->collision_bih;
9883                 const bih_leaf_t *bihleaf;
9884                 float vertex3f[3][3];
9885                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9886                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9887                 {
9888                         if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs))
9889                                 continue;
9890                         switch (bihleaf->type)
9891                         {
9892                         case BIH_BRUSH:
9893                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9894                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9895                                 {
9896                                         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);
9897                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9898                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9899                                 }
9900                                 break;
9901                         case BIH_COLLISIONTRIANGLE:
9902                                 triangleindex = bihleaf->itemindex;
9903                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9904                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9905                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9906                                 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);
9907                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9908                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9909                                 break;
9910                         case BIH_RENDERTRIANGLE:
9911                                 triangleindex = bihleaf->itemindex;
9912                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9913                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9914                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9915                                 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);
9916                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9917                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9918                                 break;
9919                         }
9920                 }
9921         }
9922
9923         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9924
9925 #ifndef USE_GLES2
9926         if (r_showtris.value > 0 && qglPolygonMode)
9927         {
9928                 if (r_showdisabledepthtest.integer)
9929                 {
9930                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9931                         GL_DepthMask(false);
9932                 }
9933                 else
9934                 {
9935                         GL_BlendFunc(GL_ONE, GL_ZERO);
9936                         GL_DepthMask(true);
9937                 }
9938                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9939                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9940                 {
9941                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9942                                 continue;
9943                         surface = model->data_surfaces + j;
9944                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9945                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9946                         {
9947                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9948                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9949                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9950                                 else if (ent == r_refdef.scene.worldentity)
9951                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9952                                 else
9953                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9954                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9955                                 RSurf_DrawBatch();
9956                         }
9957                 }
9958                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9959                 rsurface.texture = NULL;
9960         }
9961
9962 # if 0
9963         // FIXME!  implement r_shownormals with just triangles
9964         if (r_shownormals.value != 0 && qglBegin)
9965         {
9966                 int l, k;
9967                 vec3_t v;
9968                 if (r_showdisabledepthtest.integer)
9969                 {
9970                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9971                         GL_DepthMask(false);
9972                 }
9973                 else
9974                 {
9975                         GL_BlendFunc(GL_ONE, GL_ZERO);
9976                         GL_DepthMask(true);
9977                 }
9978                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9979                 {
9980                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9981                                 continue;
9982                         surface = model->data_surfaces + j;
9983                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9984                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9985                         {
9986                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9987                                 qglBegin(GL_LINES);
9988                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9989                                 {
9990                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9991                                         {
9992                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9993                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9994                                                 qglVertex3f(v[0], v[1], v[2]);
9995                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9996                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9997                                                 qglVertex3f(v[0], v[1], v[2]);
9998                                         }
9999                                 }
10000                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10001                                 {
10002                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10003                                         {
10004                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10005                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10006                                                 qglVertex3f(v[0], v[1], v[2]);
10007                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10008                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10009                                                 qglVertex3f(v[0], v[1], v[2]);
10010                                         }
10011                                 }
10012                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10013                                 {
10014                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10015                                         {
10016                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10017                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10018                                                 qglVertex3f(v[0], v[1], v[2]);
10019                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10020                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10021                                                 qglVertex3f(v[0], v[1], v[2]);
10022                                         }
10023                                 }
10024                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10025                                 {
10026                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10027                                         {
10028                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10029                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10030                                                 qglVertex3f(v[0], v[1], v[2]);
10031                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10032                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10033                                                 qglVertex3f(v[0], v[1], v[2]);
10034                                         }
10035                                 }
10036                                 qglEnd();
10037                                 CHECKGLERROR
10038                         }
10039                 }
10040                 rsurface.texture = NULL;
10041         }
10042 # endif
10043 #endif
10044 }
10045
10046 int r_maxsurfacelist = 0;
10047 const msurface_t **r_surfacelist = NULL;
10048 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
10049 {
10050         int i, j, flagsmask;
10051         model_t *model = ent->model;
10052         msurface_t *surfaces;
10053         unsigned char *update;
10054         int numsurfacelist = 0;
10055         if (model == NULL)
10056                 return;
10057
10058         if (r_maxsurfacelist < model->num_surfaces)
10059         {
10060                 r_maxsurfacelist = model->num_surfaces;
10061                 if (r_surfacelist)
10062                         Mem_Free((msurface_t **)r_surfacelist);
10063                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10064         }
10065
10066         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10067                 RSurf_ActiveModelEntity(ent, false, false, false);
10068         else if (prepass)
10069                 RSurf_ActiveModelEntity(ent, true, true, true);
10070         else if (depthonly)
10071                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10072         else
10073                 RSurf_ActiveModelEntity(ent, true, true, false);
10074
10075         surfaces = model->data_surfaces;
10076         update = model->brushq1.lightmapupdateflags;
10077
10078         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10079
10080         if (debug)
10081         {
10082                 R_DrawDebugModel();
10083                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10084                 return;
10085         }
10086
10087         // check if this is an empty model
10088         if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
10089                 return;
10090
10091         rsurface.lightmaptexture = NULL;
10092         rsurface.deluxemaptexture = NULL;
10093         rsurface.uselightmaptexture = false;
10094         rsurface.texture = NULL;
10095         rsurface.rtlight = NULL;
10096         numsurfacelist = 0;
10097
10098         // add visible surfaces to draw list
10099         if (ent == r_refdef.scene.worldentity)
10100         {
10101                 // for the world entity, check surfacevisible
10102                 for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
10103                 {
10104                         j = model->modelsurfaces_sorted[i];
10105                         if (r_refdef.viewcache.world_surfacevisible[j])
10106                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10107                 }
10108
10109                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10110                 if (!numsurfacelist)
10111                 {
10112                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10113                         return;
10114                 }
10115         }
10116         else if (ui)
10117         {
10118                 // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
10119                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10120                         r_surfacelist[numsurfacelist++] = surfaces + i;
10121         }
10122         else
10123         {
10124                 // add all surfaces
10125                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10126                         r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
10127         }
10128
10129         /*
10130          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10131          * using style chains because most styles do not change on most frames, and most
10132          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10133          * break this rule and animate most surfaces.
10134          */
10135         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10136         {
10137                 model_brush_lightstyleinfo_t *style;
10138
10139                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10140                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10141                 {
10142                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10143                         {
10144                                 int* list = style->surfacelist;
10145                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10146                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10147                                 for (j = 0; j < style->numsurfaces; j++)
10148                                         update[list[j]] = true;
10149                         }
10150                 }
10151                 // Now check if update flags are set on any surfaces that are visible
10152                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10153                 {
10154                         /*
10155                          * We can do less frequent texture uploads (approximately 10hz for animated
10156                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10157                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10158                          * use model->num_surfaces, not nummodelsurfaces.
10159                          */
10160                         for (i = 0; i < model->num_surfaces;i++)
10161                                 if (update[i])
10162                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10163                 }
10164                 else
10165                 {
10166                         for (i = 0; i < numsurfacelist; i++)
10167                                 if (update[r_surfacelist[i] - surfaces])
10168                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10169                 }
10170         }
10171
10172         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10173
10174         // add to stats if desired
10175         if (r_speeds.integer && !skysurfaces && !depthonly)
10176         {
10177                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10178                 for (j = 0;j < numsurfacelist;j++)
10179                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10180         }
10181
10182         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10183 }
10184
10185 void R_DebugLine(vec3_t start, vec3_t end)
10186 {
10187         model_t *mod = CL_Mesh_UI();
10188         msurface_t *surf;
10189         int e0, e1, e2, e3;
10190         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10191         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10192         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10193         vec4_t w[2], s[2];
10194
10195         // transform to screen coords first
10196         Vector4Set(w[0], start[0], start[1], start[2], 1);
10197         Vector4Set(w[1], end[0], end[1], end[2], 1);
10198         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10199         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10200         x1 = s[0][0] * vid_conwidth.value / vid.width;
10201         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10202         x2 = s[1][0] * vid_conwidth.value / vid.width;
10203         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10204         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10205
10206         // add the line to the UI mesh for drawing later
10207
10208         // width is measured in real pixels
10209         if (fabs(x2 - x1) > fabs(y2 - y1))
10210         {
10211                 offsetx = 0;
10212                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10213         }
10214         else
10215         {
10216                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10217                 offsety = 0;
10218         }
10219         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);
10220         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10221         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10222         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10223         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10224         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10225         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10226
10227 }
10228
10229
10230 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10231 {
10232         static texture_t texture;
10233
10234         // fake enough texture and surface state to render this geometry
10235
10236         texture.update_lastrenderframe = -1; // regenerate this texture
10237         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10238         texture.basealpha = 1.0f;
10239         texture.currentskinframe = skinframe;
10240         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10241         texture.offsetmapping = OFFSETMAPPING_OFF;
10242         texture.offsetscale = 1;
10243         texture.specularscalemod = 1;
10244         texture.specularpowermod = 1;
10245         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10246
10247         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10248 }
10249
10250 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10251 {
10252         static msurface_t surface;
10253         const msurface_t *surfacelist = &surface;
10254
10255         // fake enough texture and surface state to render this geometry
10256         surface.texture = texture;
10257         surface.num_triangles = numtriangles;
10258         surface.num_firsttriangle = firsttriangle;
10259         surface.num_vertices = numvertices;
10260         surface.num_firstvertex = firstvertex;
10261
10262         // now render it
10263         rsurface.texture = R_GetCurrentTexture(surface.texture);
10264         rsurface.lightmaptexture = NULL;
10265         rsurface.deluxemaptexture = NULL;
10266         rsurface.uselightmaptexture = false;
10267         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10268 }