]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
cmd: Use reentrant mutex for cbufs. Fixes deadlock when expanding aliases in some...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_nolerp_list = {CVAR_CLIENT | CVAR_SAVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
208 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
210
211 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
213
214 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
216 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
217 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
220
221 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
228 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
229 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
230 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
231
232 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
233
234 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
235
236 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
237
238 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
239
240 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
241 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
242 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
244
245 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
247
248 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
249
250 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
251 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
252 {
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
256         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
257 };
258
259 extern cvar_t v_glslgamma_2d;
260
261 extern qboolean v_flipped_state;
262
263 r_framebufferstate_t r_fb;
264
265 /// shadow volume bsp struct with automatically growing nodes buffer
266 svbsp_t r_svbsp;
267
268 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
269
270 rtexture_t *r_texture_blanknormalmap;
271 rtexture_t *r_texture_white;
272 rtexture_t *r_texture_grey128;
273 rtexture_t *r_texture_black;
274 rtexture_t *r_texture_notexture;
275 rtexture_t *r_texture_whitecube;
276 rtexture_t *r_texture_normalizationcube;
277 rtexture_t *r_texture_fogattenuation;
278 rtexture_t *r_texture_fogheighttexture;
279 rtexture_t *r_texture_gammaramps;
280 unsigned int r_texture_gammaramps_serial;
281 //rtexture_t *r_texture_fogintensity;
282 rtexture_t *r_texture_reflectcube;
283
284 // TODO: hash lookups?
285 typedef struct cubemapinfo_s
286 {
287         char basename[64];
288         rtexture_t *texture;
289 }
290 cubemapinfo_t;
291
292 int r_texture_numcubemaps;
293 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
294
295 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
296 unsigned int r_numqueries;
297 unsigned int r_maxqueries;
298
299 typedef struct r_qwskincache_s
300 {
301         char name[MAX_QPATH];
302         skinframe_t *skinframe;
303 }
304 r_qwskincache_t;
305
306 static r_qwskincache_t *r_qwskincache;
307 static int r_qwskincache_size;
308
309 /// vertex coordinates for a quad that covers the screen exactly
310 extern const float r_screenvertex3f[12];
311 const float r_screenvertex3f[12] =
312 {
313         0, 0, 0,
314         1, 0, 0,
315         1, 1, 0,
316         0, 1, 0
317 };
318
319 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
320 {
321         int i;
322         for (i = 0;i < verts;i++)
323         {
324                 out[0] = in[0] * r;
325                 out[1] = in[1] * g;
326                 out[2] = in[2] * b;
327                 out[3] = in[3];
328                 in += 4;
329                 out += 4;
330         }
331 }
332
333 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
334 {
335         int i;
336         for (i = 0;i < verts;i++)
337         {
338                 out[0] = r;
339                 out[1] = g;
340                 out[2] = b;
341                 out[3] = a;
342                 out += 4;
343         }
344 }
345
346 // FIXME: move this to client?
347 void FOG_clear(void)
348 {
349         if (gamemode == GAME_NEHAHRA)
350         {
351                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
352                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
353                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
354                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
355                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
356         }
357         r_refdef.fog_density = 0;
358         r_refdef.fog_red = 0;
359         r_refdef.fog_green = 0;
360         r_refdef.fog_blue = 0;
361         r_refdef.fog_alpha = 1;
362         r_refdef.fog_start = 0;
363         r_refdef.fog_end = 16384;
364         r_refdef.fog_height = 1<<30;
365         r_refdef.fog_fadedepth = 128;
366         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
367 }
368
369 static void R_BuildBlankTextures(void)
370 {
371         unsigned char data[4];
372         data[2] = 128; // normal X
373         data[1] = 128; // normal Y
374         data[0] = 255; // normal Z
375         data[3] = 255; // height
376         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
377         data[0] = 255;
378         data[1] = 255;
379         data[2] = 255;
380         data[3] = 255;
381         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
382         data[0] = 128;
383         data[1] = 128;
384         data[2] = 128;
385         data[3] = 255;
386         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
387         data[0] = 0;
388         data[1] = 0;
389         data[2] = 0;
390         data[3] = 255;
391         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
392 }
393
394 static void R_BuildNoTexture(void)
395 {
396         int x, y;
397         unsigned char pix[16][16][4];
398         // this makes a light grey/dark grey checkerboard texture
399         for (y = 0;y < 16;y++)
400         {
401                 for (x = 0;x < 16;x++)
402                 {
403                         if ((y < 8) ^ (x < 8))
404                         {
405                                 pix[y][x][0] = 128;
406                                 pix[y][x][1] = 128;
407                                 pix[y][x][2] = 128;
408                                 pix[y][x][3] = 255;
409                         }
410                         else
411                         {
412                                 pix[y][x][0] = 64;
413                                 pix[y][x][1] = 64;
414                                 pix[y][x][2] = 64;
415                                 pix[y][x][3] = 255;
416                         }
417                 }
418         }
419         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
420 }
421
422 static void R_BuildWhiteCube(void)
423 {
424         unsigned char data[6*1*1*4];
425         memset(data, 255, sizeof(data));
426         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
427 }
428
429 static void R_BuildNormalizationCube(void)
430 {
431         int x, y, side;
432         vec3_t v;
433         vec_t s, t, intensity;
434 #define NORMSIZE 64
435         unsigned char *data;
436         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
437         for (side = 0;side < 6;side++)
438         {
439                 for (y = 0;y < NORMSIZE;y++)
440                 {
441                         for (x = 0;x < NORMSIZE;x++)
442                         {
443                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
445                                 switch(side)
446                                 {
447                                 default:
448                                 case 0:
449                                         v[0] = 1;
450                                         v[1] = -t;
451                                         v[2] = -s;
452                                         break;
453                                 case 1:
454                                         v[0] = -1;
455                                         v[1] = -t;
456                                         v[2] = s;
457                                         break;
458                                 case 2:
459                                         v[0] = s;
460                                         v[1] = 1;
461                                         v[2] = t;
462                                         break;
463                                 case 3:
464                                         v[0] = s;
465                                         v[1] = -1;
466                                         v[2] = -t;
467                                         break;
468                                 case 4:
469                                         v[0] = s;
470                                         v[1] = -t;
471                                         v[2] = 1;
472                                         break;
473                                 case 5:
474                                         v[0] = -s;
475                                         v[1] = -t;
476                                         v[2] = -1;
477                                         break;
478                                 }
479                                 intensity = 127.0f / sqrt(DotProduct(v, v));
480                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
481                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
482                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
483                                 data[((side*64+y)*64+x)*4+3] = 255;
484                         }
485                 }
486         }
487         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
488         Mem_Free(data);
489 }
490
491 static void R_BuildFogTexture(void)
492 {
493         int x, b;
494 #define FOGWIDTH 256
495         unsigned char data1[FOGWIDTH][4];
496         //unsigned char data2[FOGWIDTH][4];
497         double d, r, alpha;
498
499         r_refdef.fogmasktable_start = r_refdef.fog_start;
500         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
501         r_refdef.fogmasktable_range = r_refdef.fogrange;
502         r_refdef.fogmasktable_density = r_refdef.fog_density;
503
504         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
505         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
506         {
507                 d = (x * r - r_refdef.fogmasktable_start);
508                 if(developer_extra.integer)
509                         Con_DPrintf("%f ", d);
510                 d = max(0, d);
511                 if (r_fog_exp2.integer)
512                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
513                 else
514                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
515                 if(developer_extra.integer)
516                         Con_DPrintf(" : %f ", alpha);
517                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
518                 if(developer_extra.integer)
519                         Con_DPrintf(" = %f\n", alpha);
520                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
521         }
522
523         for (x = 0;x < FOGWIDTH;x++)
524         {
525                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
526                 data1[x][0] = b;
527                 data1[x][1] = b;
528                 data1[x][2] = b;
529                 data1[x][3] = 255;
530                 //data2[x][0] = 255 - b;
531                 //data2[x][1] = 255 - b;
532                 //data2[x][2] = 255 - b;
533                 //data2[x][3] = 255;
534         }
535         if (r_texture_fogattenuation)
536         {
537                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
539         }
540         else
541         {
542                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
543                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
544         }
545 }
546
547 static void R_BuildFogHeightTexture(void)
548 {
549         unsigned char *inpixels;
550         int size;
551         int x;
552         int y;
553         int j;
554         float c[4];
555         float f;
556         inpixels = NULL;
557         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
558         if (r_refdef.fogheighttexturename[0])
559                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
560         if (!inpixels)
561         {
562                 r_refdef.fog_height_tablesize = 0;
563                 if (r_texture_fogheighttexture)
564                         R_FreeTexture(r_texture_fogheighttexture);
565                 r_texture_fogheighttexture = NULL;
566                 if (r_refdef.fog_height_table2d)
567                         Mem_Free(r_refdef.fog_height_table2d);
568                 r_refdef.fog_height_table2d = NULL;
569                 if (r_refdef.fog_height_table1d)
570                         Mem_Free(r_refdef.fog_height_table1d);
571                 r_refdef.fog_height_table1d = NULL;
572                 return;
573         }
574         size = image_width;
575         r_refdef.fog_height_tablesize = size;
576         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
577         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
578         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
579         Mem_Free(inpixels);
580         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
581         // average fog color table accounting for every fog layer between a point
582         // and the camera.  (Note: attenuation is handled separately!)
583         for (y = 0;y < size;y++)
584         {
585                 for (x = 0;x < size;x++)
586                 {
587                         Vector4Clear(c);
588                         f = 0;
589                         if (x < y)
590                         {
591                                 for (j = x;j <= y;j++)
592                                 {
593                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
594                                         f++;
595                                 }
596                         }
597                         else
598                         {
599                                 for (j = x;j >= y;j--)
600                                 {
601                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
602                                         f++;
603                                 }
604                         }
605                         f = 1.0f / f;
606                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
609                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
610                 }
611         }
612         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
613 }
614
615 //=======================================================================================================================================================
616
617 static const char *builtinshaderstrings[] =
618 {
619 #include "shader_glsl.h"
620 0
621 };
622
623 //=======================================================================================================================================================
624
625 typedef struct shaderpermutationinfo_s
626 {
627         const char *pretext;
628         const char *name;
629 }
630 shaderpermutationinfo_t;
631
632 typedef struct shadermodeinfo_s
633 {
634         const char *sourcebasename;
635         const char *extension;
636         const char **builtinshaderstrings;
637         const char *pretext;
638         const char *name;
639         char *filename;
640         char *builtinstring;
641         int builtincrc;
642 }
643 shadermodeinfo_t;
644
645 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
646 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
647 {
648         {"#define USEDIFFUSE\n", " diffuse"},
649         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
650         {"#define USEVIEWTINT\n", " viewtint"},
651         {"#define USECOLORMAPPING\n", " colormapping"},
652         {"#define USESATURATION\n", " saturation"},
653         {"#define USEFOGINSIDE\n", " foginside"},
654         {"#define USEFOGOUTSIDE\n", " fogoutside"},
655         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
656         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
657         {"#define USEGAMMARAMPS\n", " gammaramps"},
658         {"#define USECUBEFILTER\n", " cubefilter"},
659         {"#define USEGLOW\n", " glow"},
660         {"#define USEBLOOM\n", " bloom"},
661         {"#define USESPECULAR\n", " specular"},
662         {"#define USEPOSTPROCESSING\n", " postprocessing"},
663         {"#define USEREFLECTION\n", " reflection"},
664         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
665         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
666         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
667         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
668         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
669         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
670         {"#define USEALPHAKILL\n", " alphakill"},
671         {"#define USEREFLECTCUBE\n", " reflectcube"},
672         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
673         {"#define USEBOUNCEGRID\n", " bouncegrid"},
674         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
675         {"#define USETRIPPY\n", " trippy"},
676         {"#define USEDEPTHRGB\n", " depthrgb"},
677         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
678         {"#define USESKELETAL\n", " skeletal"},
679         {"#define USEOCCLUDE\n", " occlude"}
680 };
681
682 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
683 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
684 {
685         // SHADERLANGUAGE_GLSL
686         {
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
703                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
704         },
705 };
706
707 struct r_glsl_permutation_s;
708 typedef struct r_glsl_permutation_s
709 {
710         /// hash lookup data
711         struct r_glsl_permutation_s *hashnext;
712         unsigned int mode;
713         uint64_t permutation;
714
715         /// indicates if we have tried compiling this permutation already
716         qboolean compiled;
717         /// 0 if compilation failed
718         int program;
719         // texture units assigned to each detected uniform
720         int tex_Texture_First;
721         int tex_Texture_Second;
722         int tex_Texture_GammaRamps;
723         int tex_Texture_Normal;
724         int tex_Texture_Color;
725         int tex_Texture_Gloss;
726         int tex_Texture_Glow;
727         int tex_Texture_SecondaryNormal;
728         int tex_Texture_SecondaryColor;
729         int tex_Texture_SecondaryGloss;
730         int tex_Texture_SecondaryGlow;
731         int tex_Texture_Pants;
732         int tex_Texture_Shirt;
733         int tex_Texture_FogHeightTexture;
734         int tex_Texture_FogMask;
735         int tex_Texture_LightGrid;
736         int tex_Texture_Lightmap;
737         int tex_Texture_Deluxemap;
738         int tex_Texture_Attenuation;
739         int tex_Texture_Cube;
740         int tex_Texture_Refraction;
741         int tex_Texture_Reflection;
742         int tex_Texture_ShadowMap2D;
743         int tex_Texture_CubeProjection;
744         int tex_Texture_ScreenNormalMap;
745         int tex_Texture_ScreenDiffuse;
746         int tex_Texture_ScreenSpecular;
747         int tex_Texture_ReflectMask;
748         int tex_Texture_ReflectCube;
749         int tex_Texture_BounceGrid;
750         /// locations of detected uniforms in program object, or -1 if not found
751         int loc_Texture_First;
752         int loc_Texture_Second;
753         int loc_Texture_GammaRamps;
754         int loc_Texture_Normal;
755         int loc_Texture_Color;
756         int loc_Texture_Gloss;
757         int loc_Texture_Glow;
758         int loc_Texture_SecondaryNormal;
759         int loc_Texture_SecondaryColor;
760         int loc_Texture_SecondaryGloss;
761         int loc_Texture_SecondaryGlow;
762         int loc_Texture_Pants;
763         int loc_Texture_Shirt;
764         int loc_Texture_FogHeightTexture;
765         int loc_Texture_FogMask;
766         int loc_Texture_LightGrid;
767         int loc_Texture_Lightmap;
768         int loc_Texture_Deluxemap;
769         int loc_Texture_Attenuation;
770         int loc_Texture_Cube;
771         int loc_Texture_Refraction;
772         int loc_Texture_Reflection;
773         int loc_Texture_ShadowMap2D;
774         int loc_Texture_CubeProjection;
775         int loc_Texture_ScreenNormalMap;
776         int loc_Texture_ScreenDiffuse;
777         int loc_Texture_ScreenSpecular;
778         int loc_Texture_ReflectMask;
779         int loc_Texture_ReflectCube;
780         int loc_Texture_BounceGrid;
781         int loc_Alpha;
782         int loc_BloomBlur_Parameters;
783         int loc_ClientTime;
784         int loc_Color_Ambient;
785         int loc_Color_Diffuse;
786         int loc_Color_Specular;
787         int loc_Color_Glow;
788         int loc_Color_Pants;
789         int loc_Color_Shirt;
790         int loc_DeferredColor_Ambient;
791         int loc_DeferredColor_Diffuse;
792         int loc_DeferredColor_Specular;
793         int loc_DeferredMod_Diffuse;
794         int loc_DeferredMod_Specular;
795         int loc_DistortScaleRefractReflect;
796         int loc_EyePosition;
797         int loc_FogColor;
798         int loc_FogHeightFade;
799         int loc_FogPlane;
800         int loc_FogPlaneViewDist;
801         int loc_FogRangeRecip;
802         int loc_LightColor;
803         int loc_LightDir;
804         int loc_LightGridMatrix;
805         int loc_LightGridNormalMatrix;
806         int loc_LightPosition;
807         int loc_OffsetMapping_ScaleSteps;
808         int loc_OffsetMapping_LodDistance;
809         int loc_OffsetMapping_Bias;
810         int loc_PixelSize;
811         int loc_ReflectColor;
812         int loc_ReflectFactor;
813         int loc_ReflectOffset;
814         int loc_RefractColor;
815         int loc_Saturation;
816         int loc_ScreenCenterRefractReflect;
817         int loc_ScreenScaleRefractReflect;
818         int loc_ScreenToDepth;
819         int loc_ShadowMap_Parameters;
820         int loc_ShadowMap_TextureScale;
821         int loc_SpecularPower;
822         int loc_Skeletal_Transform12;
823         int loc_UserVec1;
824         int loc_UserVec2;
825         int loc_UserVec3;
826         int loc_UserVec4;
827         int loc_ColorFringe;
828         int loc_ViewTintColor;
829         int loc_ViewToLight;
830         int loc_ModelToLight;
831         int loc_TexMatrix;
832         int loc_BackgroundTexMatrix;
833         int loc_ModelViewProjectionMatrix;
834         int loc_ModelViewMatrix;
835         int loc_PixelToScreenTexCoord;
836         int loc_ModelToReflectCube;
837         int loc_ShadowMapMatrix;
838         int loc_BloomColorSubtract;
839         int loc_NormalmapScrollBlend;
840         int loc_BounceGridMatrix;
841         int loc_BounceGridIntensity;
842         /// uniform block bindings
843         int ubibind_Skeletal_Transform12_UniformBlock;
844         /// uniform block indices
845         int ubiloc_Skeletal_Transform12_UniformBlock;
846 }
847 r_glsl_permutation_t;
848
849 #define SHADERPERMUTATION_HASHSIZE 256
850
851
852 // non-degradable "lightweight" shader parameters to keep the permutations simpler
853 // these can NOT degrade! only use for simple stuff
854 enum
855 {
856         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
857         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
858         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
859         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
860         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
861         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
862         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
863         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
864         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
865         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
866         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
867         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
868         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
869         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
870 };
871 #define SHADERSTATICPARMS_COUNT 14
872
873 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
874 static int shaderstaticparms_count = 0;
875
876 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
877 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
878
879 extern qboolean r_shadow_shadowmapsampler;
880 extern int r_shadow_shadowmappcf;
881 qboolean R_CompileShader_CheckStaticParms(void)
882 {
883         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
884         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
885         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
886
887         // detect all
888         if (r_glsl_saturation_redcompensate.integer)
889                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
890         if (r_glsl_vertextextureblend_usebothalphas.integer)
891                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
892         if (r_shadow_glossexact.integer)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
894         if (r_glsl_postprocess.integer)
895         {
896                 if (r_glsl_postprocess_uservec1_enable.integer)
897                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
898                 if (r_glsl_postprocess_uservec2_enable.integer)
899                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
900                 if (r_glsl_postprocess_uservec3_enable.integer)
901                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
902                 if (r_glsl_postprocess_uservec4_enable.integer)
903                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
904         }
905         if (r_fxaa.integer)
906                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
907         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
908                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
909
910         if (r_shadow_shadowmapsampler)
911                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
912         if (r_shadow_shadowmappcf > 1)
913                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
914         else if (r_shadow_shadowmappcf)
915                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
916         if (r_celshading.integer)
917                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
918         if (r_celoutlines.integer)
919                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
920
921         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
922 }
923
924 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
925         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
926                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
927         else \
928                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
929 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
930 {
931         shaderstaticparms_count = 0;
932
933         // emit all
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
947         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
948 }
949
950 /// information about each possible shader permutation
951 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
952 /// currently selected permutation
953 r_glsl_permutation_t *r_glsl_permutation;
954 /// storage for permutations linked in the hash table
955 memexpandablearray_t r_glsl_permutationarray;
956
957 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
958 {
959         //unsigned int hashdepth = 0;
960         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
961         r_glsl_permutation_t *p;
962         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
963         {
964                 if (p->mode == mode && p->permutation == permutation)
965                 {
966                         //if (hashdepth > 10)
967                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
968                         return p;
969                 }
970                 //hashdepth++;
971         }
972         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
973         p->mode = mode;
974         p->permutation = permutation;
975         p->hashnext = r_glsl_permutationhash[mode][hashindex];
976         r_glsl_permutationhash[mode][hashindex] = p;
977         //if (hashdepth > 10)
978         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
979         return p;
980 }
981
982 static char *R_ShaderStrCat(const char **strings)
983 {
984         char *string, *s;
985         const char **p = strings;
986         const char *t;
987         size_t len = 0;
988         for (p = strings;(t = *p);p++)
989                 len += strlen(t);
990         len++;
991         s = string = (char *)Mem_Alloc(r_main_mempool, len);
992         len = 0;
993         for (p = strings;(t = *p);p++)
994         {
995                 len = strlen(t);
996                 memcpy(s, t, len);
997                 s += len;
998         }
999         *s = 0;
1000         return string;
1001 }
1002
1003 static char *R_ShaderStrCat(const char **strings);
1004 static void R_InitShaderModeInfo(void)
1005 {
1006         int i, language;
1007         shadermodeinfo_t *modeinfo;
1008         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1009         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1010         {
1011                 for (i = 0; i < SHADERMODE_COUNT; i++)
1012                 {
1013                         char filename[MAX_QPATH];
1014                         modeinfo = &shadermodeinfo[language][i];
1015                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1016                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1017                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1018                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1019                 }
1020         }
1021 }
1022
1023 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1024 {
1025         char *shaderstring;
1026         // if the mode has no filename we have to return the builtin string
1027         if (builtinonly || !modeinfo->filename)
1028                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1029         // note that FS_LoadFile appends a 0 byte to make it a valid string
1030         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1031         if (shaderstring)
1032         {
1033                 if (printfromdisknotice)
1034                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1035                 return shaderstring;
1036         }
1037         // fall back to builtinstring
1038         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1039 }
1040
1041 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1042 {
1043         int i;
1044         int ubibind;
1045         int sampler;
1046         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1047         char *sourcestring;
1048         char permutationname[256];
1049         int vertstrings_count = 0;
1050         int geomstrings_count = 0;
1051         int fragstrings_count = 0;
1052         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1053         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1054         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1055
1056         if (p->compiled)
1057                 return;
1058         p->compiled = true;
1059         p->program = 0;
1060
1061         permutationname[0] = 0;
1062         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1063
1064         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1065
1066         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1067         if(vid.support.glshaderversion >= 140)
1068         {
1069                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1070                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1071                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1072                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1073                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1074                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1075         }
1076         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1077         else if(vid.support.glshaderversion >= 130)
1078         {
1079                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1080                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1081                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1082                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1083                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1084                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1085         }
1086         // if we can do #version 120, we should (this adds the invariant keyword)
1087         else if(vid.support.glshaderversion >= 120)
1088         {
1089                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1090                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1091                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1092                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1093                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1094                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1095         }
1096         // GLES also adds several things from GLSL120
1097         switch(vid.renderpath)
1098         {
1099         case RENDERPATH_GLES2:
1100                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1101                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1102                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1103                 break;
1104         default:
1105                 break;
1106         }
1107
1108         // the first pretext is which type of shader to compile as
1109         // (later these will all be bound together as a program object)
1110         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1111         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1112         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1113
1114         // the second pretext is the mode (for example a light source)
1115         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1116         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1117         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1118         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1119
1120         // now add all the permutation pretexts
1121         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1122         {
1123                 if (permutation & (1ll<<i))
1124                 {
1125                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1126                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1127                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1128                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1129                 }
1130                 else
1131                 {
1132                         // keep line numbers correct
1133                         vertstrings_list[vertstrings_count++] = "\n";
1134                         geomstrings_list[geomstrings_count++] = "\n";
1135                         fragstrings_list[fragstrings_count++] = "\n";
1136                 }
1137         }
1138
1139         // add static parms
1140         R_CompileShader_AddStaticParms(mode, permutation);
1141         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1142         vertstrings_count += shaderstaticparms_count;
1143         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1144         geomstrings_count += shaderstaticparms_count;
1145         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1146         fragstrings_count += shaderstaticparms_count;
1147
1148         // now append the shader text itself
1149         vertstrings_list[vertstrings_count++] = sourcestring;
1150         geomstrings_list[geomstrings_count++] = sourcestring;
1151         fragstrings_list[fragstrings_count++] = sourcestring;
1152
1153         // we don't currently use geometry shaders for anything, so just empty the list
1154         geomstrings_count = 0;
1155
1156         // compile the shader program
1157         if (vertstrings_count + geomstrings_count + fragstrings_count)
1158                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1159         if (p->program)
1160         {
1161                 CHECKGLERROR
1162                 qglUseProgram(p->program);CHECKGLERROR
1163                 // look up all the uniform variable names we care about, so we don't
1164                 // have to look them up every time we set them
1165
1166 #if 0
1167                 // debugging aid
1168                 {
1169                         GLint activeuniformindex = 0;
1170                         GLint numactiveuniforms = 0;
1171                         char uniformname[128];
1172                         GLsizei uniformnamelength = 0;
1173                         GLint uniformsize = 0;
1174                         GLenum uniformtype = 0;
1175                         memset(uniformname, 0, sizeof(uniformname));
1176                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1177                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1178                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1179                         {
1180                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1181                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1182                         }
1183                 }
1184 #endif
1185
1186                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1187                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1188                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1189                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1190                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1191                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1192                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1193                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1194                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1195                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1196                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1197                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1198                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1199                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1200                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1201                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1202                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1203                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1204                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1205                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1206                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1207                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1208                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1209                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1210                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1211                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1212                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1213                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1214                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1215                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1216                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1217                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1218                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1219                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1220                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1221                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1222                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1223                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1224                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1225                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1226                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1227                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1228                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1229                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1230                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1231                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1232                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1233                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1234                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1235                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1236                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1237                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1238                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1239                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1240                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1241                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1242                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1243                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1244                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1245                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1246                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1247                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1248                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1249                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1250                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1251                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1252                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1253                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1254                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1255                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1256                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1257                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1258                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1259                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1260                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1261                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1262                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1263                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1264                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1265                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1266                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1267                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1268                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1269                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1270                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1271                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1272                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1273                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1274                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1275                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1276                 // initialize the samplers to refer to the texture units we use
1277                 p->tex_Texture_First = -1;
1278                 p->tex_Texture_Second = -1;
1279                 p->tex_Texture_GammaRamps = -1;
1280                 p->tex_Texture_Normal = -1;
1281                 p->tex_Texture_Color = -1;
1282                 p->tex_Texture_Gloss = -1;
1283                 p->tex_Texture_Glow = -1;
1284                 p->tex_Texture_SecondaryNormal = -1;
1285                 p->tex_Texture_SecondaryColor = -1;
1286                 p->tex_Texture_SecondaryGloss = -1;
1287                 p->tex_Texture_SecondaryGlow = -1;
1288                 p->tex_Texture_Pants = -1;
1289                 p->tex_Texture_Shirt = -1;
1290                 p->tex_Texture_FogHeightTexture = -1;
1291                 p->tex_Texture_FogMask = -1;
1292                 p->tex_Texture_LightGrid = -1;
1293                 p->tex_Texture_Lightmap = -1;
1294                 p->tex_Texture_Deluxemap = -1;
1295                 p->tex_Texture_Attenuation = -1;
1296                 p->tex_Texture_Cube = -1;
1297                 p->tex_Texture_Refraction = -1;
1298                 p->tex_Texture_Reflection = -1;
1299                 p->tex_Texture_ShadowMap2D = -1;
1300                 p->tex_Texture_CubeProjection = -1;
1301                 p->tex_Texture_ScreenNormalMap = -1;
1302                 p->tex_Texture_ScreenDiffuse = -1;
1303                 p->tex_Texture_ScreenSpecular = -1;
1304                 p->tex_Texture_ReflectMask = -1;
1305                 p->tex_Texture_ReflectCube = -1;
1306                 p->tex_Texture_BounceGrid = -1;
1307                 // bind the texture samplers in use
1308                 sampler = 0;
1309                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1310                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1311                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1312                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1313                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1314                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1315                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1316                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1317                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1318                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1319                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1320                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1321                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1322                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1323                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1324                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1325                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1326                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1327                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1328                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1329                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1330                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1331                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1332                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1333                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1334                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1335                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1336                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1337                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1338                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1339                 // get the uniform block indices so we can bind them
1340                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1341 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1342                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1343 #endif
1344                 // clear the uniform block bindings
1345                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1346                 // bind the uniform blocks in use
1347                 ubibind = 0;
1348 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1349                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1350 #endif
1351                 // we're done compiling and setting up the shader, at least until it is used
1352                 CHECKGLERROR
1353                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1354         }
1355         else
1356                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1357
1358         // free the strings
1359         if (sourcestring)
1360                 Mem_Free(sourcestring);
1361 }
1362
1363 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1364 {
1365         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1366         if (r_glsl_permutation != perm)
1367         {
1368                 r_glsl_permutation = perm;
1369                 if (!r_glsl_permutation->program)
1370                 {
1371                         if (!r_glsl_permutation->compiled)
1372                         {
1373                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1374                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1375                         }
1376                         if (!r_glsl_permutation->program)
1377                         {
1378                                 // remove features until we find a valid permutation
1379                                 int i;
1380                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1381                                 {
1382                                         // reduce i more quickly whenever it would not remove any bits
1383                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1384                                         if (!(permutation & j))
1385                                                 continue;
1386                                         permutation -= j;
1387                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1388                                         if (!r_glsl_permutation->compiled)
1389                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1390                                         if (r_glsl_permutation->program)
1391                                                 break;
1392                                 }
1393                                 if (i >= SHADERPERMUTATION_COUNT)
1394                                 {
1395                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1396                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1397                                         qglUseProgram(0);CHECKGLERROR
1398                                         return; // no bit left to clear, entire mode is broken
1399                                 }
1400                         }
1401                 }
1402                 CHECKGLERROR
1403                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1404         }
1405         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1406         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1407         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1408         CHECKGLERROR
1409 }
1410
1411 void R_GLSL_Restart_f(cmd_state_t *cmd)
1412 {
1413         unsigned int i, limit;
1414         switch(vid.renderpath)
1415         {
1416         case RENDERPATH_GL32:
1417         case RENDERPATH_GLES2:
1418                 {
1419                         r_glsl_permutation_t *p;
1420                         r_glsl_permutation = NULL;
1421                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1422                         for (i = 0;i < limit;i++)
1423                         {
1424                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1425                                 {
1426                                         GL_Backend_FreeProgram(p->program);
1427                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1428                                 }
1429                         }
1430                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1431                 }
1432                 break;
1433         }
1434 }
1435
1436 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1437 {
1438         int i, language, mode, dupe;
1439         char *text;
1440         shadermodeinfo_t *modeinfo;
1441         qfile_t *file;
1442
1443         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1444         {
1445                 modeinfo = shadermodeinfo[language];
1446                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1447                 {
1448                         // don't dump the same file multiple times (most or all shaders come from the same file)
1449                         for (dupe = mode - 1;dupe >= 0;dupe--)
1450                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1451                                         break;
1452                         if (dupe >= 0)
1453                                 continue;
1454                         text = modeinfo[mode].builtinstring;
1455                         if (!text)
1456                                 continue;
1457                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1458                         if (file)
1459                         {
1460                                 FS_Print(file, "/* The engine may define the following macros:\n");
1461                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1462                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1463                                         FS_Print(file, modeinfo[i].pretext);
1464                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1465                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1466                                 FS_Print(file, "*/\n");
1467                                 FS_Print(file, text);
1468                                 FS_Close(file);
1469                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1470                         }
1471                         else
1472                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1473                 }
1474         }
1475 }
1476
1477 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1478 {
1479         uint64_t permutation = 0;
1480         if (r_trippy.integer && !notrippy)
1481                 permutation |= SHADERPERMUTATION_TRIPPY;
1482         permutation |= SHADERPERMUTATION_VIEWTINT;
1483         if (t)
1484                 permutation |= SHADERPERMUTATION_DIFFUSE;
1485         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1486                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1487         if (suppresstexalpha)
1488                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1489         if (vid.allowalphatocoverage)
1490                 GL_AlphaToCoverage(false);
1491         switch (vid.renderpath)
1492         {
1493         case RENDERPATH_GL32:
1494         case RENDERPATH_GLES2:
1495                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1496                 if (r_glsl_permutation->tex_Texture_First >= 0)
1497                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1498                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1499                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1500                 break;
1501         }
1502 }
1503
1504 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1505 {
1506         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1507 }
1508
1509 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1510 {
1511         uint64_t permutation = 0;
1512         if (r_trippy.integer && !notrippy)
1513                 permutation |= SHADERPERMUTATION_TRIPPY;
1514         if (depthrgb)
1515                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1516         if (skeletal)
1517                 permutation |= SHADERPERMUTATION_SKELETAL;
1518
1519         if (vid.allowalphatocoverage)
1520                 GL_AlphaToCoverage(false);
1521         switch (vid.renderpath)
1522         {
1523         case RENDERPATH_GL32:
1524         case RENDERPATH_GLES2:
1525                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1526 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1527                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1528 #endif
1529                 break;
1530         }
1531 }
1532
1533 #define BLENDFUNC_ALLOWS_COLORMOD      1
1534 #define BLENDFUNC_ALLOWS_FOG           2
1535 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1536 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1537 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1538 static int R_BlendFuncFlags(int src, int dst)
1539 {
1540         int r = 0;
1541
1542         // a blendfunc allows colormod if:
1543         // a) it can never keep the destination pixel invariant, or
1544         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1545         // this is to prevent unintended side effects from colormod
1546
1547         // a blendfunc allows fog if:
1548         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1549         // this is to prevent unintended side effects from fog
1550
1551         // these checks are the output of fogeval.pl
1552
1553         r |= BLENDFUNC_ALLOWS_COLORMOD;
1554         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1561         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1562         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1563         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1564         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1566         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1567         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1568         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1569         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1571         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1572         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1574         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1575
1576         return r;
1577 }
1578
1579 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1580 {
1581         // select a permutation of the lighting shader appropriate to this
1582         // combination of texture, entity, light source, and fogging, only use the
1583         // minimum features necessary to avoid wasting rendering time in the
1584         // fragment shader on features that are not being used
1585         uint64_t permutation = 0;
1586         unsigned int mode = 0;
1587         int blendfuncflags;
1588         texture_t *t = rsurface.texture;
1589         float m16f[16];
1590         matrix4x4_t tempmatrix;
1591         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1592         if (r_trippy.integer && !notrippy)
1593                 permutation |= SHADERPERMUTATION_TRIPPY;
1594         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1595                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1596         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1597                 permutation |= SHADERPERMUTATION_OCCLUDE;
1598         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1599                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1600         if (rsurfacepass == RSURFPASS_BACKGROUND)
1601         {
1602                 // distorted background
1603                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1604                 {
1605                         mode = SHADERMODE_WATER;
1606                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1607                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1608                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1609                         {
1610                                 // this is the right thing to do for wateralpha
1611                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1612                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1613                         }
1614                         else
1615                         {
1616                                 // this is the right thing to do for entity alpha
1617                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1619                         }
1620                 }
1621                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1622                 {
1623                         mode = SHADERMODE_REFRACTION;
1624                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1625                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1626                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1628                 }
1629                 else
1630                 {
1631                         mode = SHADERMODE_GENERIC;
1632                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1633                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1634                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1635                 }
1636                 if (vid.allowalphatocoverage)
1637                         GL_AlphaToCoverage(false);
1638         }
1639         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1640         {
1641                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1642                 {
1643                         switch(t->offsetmapping)
1644                         {
1645                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1646                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1647                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1648                         case OFFSETMAPPING_OFF: break;
1649                         }
1650                 }
1651                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1652                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1653                 // normalmap (deferred prepass), may use alpha test on diffuse
1654                 mode = SHADERMODE_DEFERREDGEOMETRY;
1655                 GL_BlendFunc(GL_ONE, GL_ZERO);
1656                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1657                 if (vid.allowalphatocoverage)
1658                         GL_AlphaToCoverage(false);
1659         }
1660         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1661         {
1662                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1663                 {
1664                         switch(t->offsetmapping)
1665                         {
1666                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1667                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1668                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1669                         case OFFSETMAPPING_OFF: break;
1670                         }
1671                 }
1672                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1673                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1674                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1675                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1676                 // light source
1677                 mode = SHADERMODE_LIGHTSOURCE;
1678                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1679                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1680                 if (VectorLength2(rtlightdiffuse) > 0)
1681                         permutation |= SHADERPERMUTATION_DIFFUSE;
1682                 if (VectorLength2(rtlightspecular) > 0)
1683                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1684                 if (r_refdef.fogenabled)
1685                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1686                 if (t->colormapping)
1687                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1688                 if (r_shadow_usingshadowmap2d)
1689                 {
1690                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1691                         if(r_shadow_shadowmapvsdct)
1692                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1693
1694                         if (r_shadow_shadowmap2ddepthbuffer)
1695                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1696                 }
1697                 if (t->reflectmasktexture)
1698                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1699                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1700                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1701                 if (vid.allowalphatocoverage)
1702                         GL_AlphaToCoverage(false);
1703         }
1704         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1705         {
1706                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1707                 {
1708                         switch(t->offsetmapping)
1709                         {
1710                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1711                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1712                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1713                         case OFFSETMAPPING_OFF: break;
1714                         }
1715                 }
1716                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1717                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1718                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1719                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1720                 // directional model lighting
1721                 mode = SHADERMODE_LIGHTGRID;
1722                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1723                         permutation |= SHADERPERMUTATION_GLOW;
1724                 permutation |= SHADERPERMUTATION_DIFFUSE;
1725                 if (t->glosstexture || t->backgroundglosstexture)
1726                         permutation |= SHADERPERMUTATION_SPECULAR;
1727                 if (r_refdef.fogenabled)
1728                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1729                 if (t->colormapping)
1730                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1731                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1732                 {
1733                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1734                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1735
1736                         if (r_shadow_shadowmap2ddepthbuffer)
1737                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1738                 }
1739                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1740                         permutation |= SHADERPERMUTATION_REFLECTION;
1741                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1742                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1743                 if (t->reflectmasktexture)
1744                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1745                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1746                 {
1747                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1748                         if (r_shadow_bouncegrid_state.directional)
1749                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1750                 }
1751                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1752                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1753                 // when using alphatocoverage, we don't need alphakill
1754                 if (vid.allowalphatocoverage)
1755                 {
1756                         if (r_transparent_alphatocoverage.integer)
1757                         {
1758                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1759                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1760                         }
1761                         else
1762                                 GL_AlphaToCoverage(false);
1763                 }
1764         }
1765         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1766         {
1767                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1768                 {
1769                         switch(t->offsetmapping)
1770                         {
1771                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1772                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1773                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1774                         case OFFSETMAPPING_OFF: break;
1775                         }
1776                 }
1777                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1778                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1779                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1780                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1781                 // directional model lighting
1782                 mode = SHADERMODE_LIGHTDIRECTION;
1783                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1784                         permutation |= SHADERPERMUTATION_GLOW;
1785                 if (VectorLength2(t->render_modellight_diffuse))
1786                         permutation |= SHADERPERMUTATION_DIFFUSE;
1787                 if (VectorLength2(t->render_modellight_specular) > 0)
1788                         permutation |= SHADERPERMUTATION_SPECULAR;
1789                 if (r_refdef.fogenabled)
1790                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1791                 if (t->colormapping)
1792                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1793                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1794                 {
1795                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1796                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1797
1798                         if (r_shadow_shadowmap2ddepthbuffer)
1799                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1800                 }
1801                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1802                         permutation |= SHADERPERMUTATION_REFLECTION;
1803                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1804                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1805                 if (t->reflectmasktexture)
1806                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1807                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1808                 {
1809                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1810                         if (r_shadow_bouncegrid_state.directional)
1811                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1812                 }
1813                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1814                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1815                 // when using alphatocoverage, we don't need alphakill
1816                 if (vid.allowalphatocoverage)
1817                 {
1818                         if (r_transparent_alphatocoverage.integer)
1819                         {
1820                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1821                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1822                         }
1823                         else
1824                                 GL_AlphaToCoverage(false);
1825                 }
1826         }
1827         else
1828         {
1829                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1830                 {
1831                         switch(t->offsetmapping)
1832                         {
1833                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1834                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1835                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1836                         case OFFSETMAPPING_OFF: break;
1837                         }
1838                 }
1839                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1840                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1841                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1842                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1843                 // lightmapped wall
1844                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1845                         permutation |= SHADERPERMUTATION_GLOW;
1846                 if (r_refdef.fogenabled && !notrippy)
1847                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1848                 if (t->colormapping)
1849                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1850                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1851                 {
1852                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1853                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1854
1855                         if (r_shadow_shadowmap2ddepthbuffer)
1856                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1857                 }
1858                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1859                         permutation |= SHADERPERMUTATION_REFLECTION;
1860                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1861                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1862                 if (t->reflectmasktexture)
1863                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1864                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1865                 {
1866                         // deluxemapping (light direction texture)
1867                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1868                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1869                         else
1870                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1871                         permutation |= SHADERPERMUTATION_DIFFUSE;
1872                         if (VectorLength2(t->render_lightmap_specular) > 0)
1873                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1874                 }
1875                 else if (r_glsl_deluxemapping.integer >= 2)
1876                 {
1877                         // fake deluxemapping (uniform light direction in tangentspace)
1878                         if (rsurface.uselightmaptexture)
1879                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1880                         else
1881                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1882                         permutation |= SHADERPERMUTATION_DIFFUSE;
1883                         if (VectorLength2(t->render_lightmap_specular) > 0)
1884                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1885                 }
1886                 else if (rsurface.uselightmaptexture)
1887                 {
1888                         // ordinary lightmapping (q1bsp, q3bsp)
1889                         mode = SHADERMODE_LIGHTMAP;
1890                 }
1891                 else
1892                 {
1893                         // ordinary vertex coloring (q3bsp)
1894                         mode = SHADERMODE_VERTEXCOLOR;
1895                 }
1896                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1897                 {
1898                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1899                         if (r_shadow_bouncegrid_state.directional)
1900                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1901                 }
1902                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1903                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1904                 // when using alphatocoverage, we don't need alphakill
1905                 if (vid.allowalphatocoverage)
1906                 {
1907                         if (r_transparent_alphatocoverage.integer)
1908                         {
1909                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1910                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1911                         }
1912                         else
1913                                 GL_AlphaToCoverage(false);
1914                 }
1915         }
1916         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1917                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1918         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !notrippy)
1919                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1920         switch(vid.renderpath)
1921         {
1922         case RENDERPATH_GL32:
1923         case RENDERPATH_GLES2:
1924                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1925                 RSurf_UploadBuffersForBatch();
1926                 // this has to be after RSurf_PrepareVerticesForBatch
1927                 if (rsurface.batchskeletaltransform3x4buffer)
1928                         permutation |= SHADERPERMUTATION_SKELETAL;
1929                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1930 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1931                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1932 #endif
1933                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1934                 if (mode == SHADERMODE_LIGHTSOURCE)
1935                 {
1936                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1937                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1938                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1939                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1940                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1941                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1942         
1943                         // additive passes are only darkened by fog, not tinted
1944                         if (r_glsl_permutation->loc_FogColor >= 0)
1945                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1946                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1947                 }
1948                 else
1949                 {
1950                         if (mode == SHADERMODE_FLATCOLOR)
1951                         {
1952                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1953                         }
1954                         else if (mode == SHADERMODE_LIGHTGRID)
1955                         {
1956                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1957                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1958                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1959                                 // other LightGrid uniforms handled below
1960                         }
1961                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1962                         {
1963                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1964                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1965                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1966                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1967                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1968                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1969                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir_local[0], t->render_modellight_lightdir_local[1], t->render_modellight_lightdir_local[2]);
1970                         }
1971                         else
1972                         {
1973                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1974                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1975                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1976                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1977                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1978                         }
1979                         // additive passes are only darkened by fog, not tinted
1980                         if (r_glsl_permutation->loc_FogColor >= 0 && !notrippy)
1981                         {
1982                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1983                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1984                                 else
1985                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1986                         }
1987                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1988                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1989                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1990                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1991                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1992                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1993                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1994                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1995                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1996                 }
1997                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1998                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1999                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
2000                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
2001                 {
2002                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
2003                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
2004                 }
2005                 else
2006                 {
2007                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2008                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2009                 }
2010
2011                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
2012                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
2013                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2014                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2015                 {
2016                         if (t->pantstexture)
2017                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2018                         else
2019                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2020                 }
2021                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2022                 {
2023                         if (t->shirttexture)
2024                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2025                         else
2026                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2027                 }
2028                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
2029                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2030                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2031                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2032                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2033                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2034                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2035                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2036                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2037                         );
2038                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
2039                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2040                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2041                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2042                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
2043                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2044                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2045                 {
2046                         float m9f[9];
2047                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2048                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2049                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2050                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2051                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2052                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2053                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2054                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2055                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2056                 }
2057
2058                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2059                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2060                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2061                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2062                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2063                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2064                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2065                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2066                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2067                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2068                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2069                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2070                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2071                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2072                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2073                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2074                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2075                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2076                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2077                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2078                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2079                 {
2080                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
2081                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
2082                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2083                 }
2084                 else
2085                 {
2086                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2087                 }
2088                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2089                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2090                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2091                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2092                 {
2093                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2094                         if (rsurface.rtlight)
2095                         {
2096                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2097                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2098                         }
2099                 }
2100                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2101                 if (r_glsl_permutation->tex_Texture_LightGrid   >= 0 && r_refdef.scene.worldmodel) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LightGrid, r_refdef.scene.worldmodel->brushq3.lightgridtexture);
2102                 CHECKGLERROR
2103                 break;
2104         }
2105 }
2106
2107 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2108 {
2109         // select a permutation of the lighting shader appropriate to this
2110         // combination of texture, entity, light source, and fogging, only use the
2111         // minimum features necessary to avoid wasting rendering time in the
2112         // fragment shader on features that are not being used
2113         uint64_t permutation = 0;
2114         unsigned int mode = 0;
2115         const float *lightcolorbase = rtlight->currentcolor;
2116         float ambientscale = rtlight->ambientscale;
2117         float diffusescale = rtlight->diffusescale;
2118         float specularscale = rtlight->specularscale;
2119         // this is the location of the light in view space
2120         vec3_t viewlightorigin;
2121         // this transforms from view space (camera) to light space (cubemap)
2122         matrix4x4_t viewtolight;
2123         matrix4x4_t lighttoview;
2124         float viewtolight16f[16];
2125         // light source
2126         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2127         if (rtlight->currentcubemap != r_texture_whitecube)
2128                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2129         if (diffusescale > 0)
2130                 permutation |= SHADERPERMUTATION_DIFFUSE;
2131         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2132                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2133         if (r_shadow_usingshadowmap2d)
2134         {
2135                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2136                 if (r_shadow_shadowmapvsdct)
2137                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2138
2139                 if (r_shadow_shadowmap2ddepthbuffer)
2140                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2141         }
2142         if (vid.allowalphatocoverage)
2143                 GL_AlphaToCoverage(false);
2144         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2145         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2146         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2147         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2148         switch(vid.renderpath)
2149         {
2150         case RENDERPATH_GL32:
2151         case RENDERPATH_GLES2:
2152                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2153                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2154                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2155                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2156                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2157                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2158                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2159                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2160                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2161                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2162                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2163
2164                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2165                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2166                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2167                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2168                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2169                 break;
2170         }
2171 }
2172
2173 #define SKINFRAME_HASH 1024
2174
2175 typedef struct
2176 {
2177         unsigned int loadsequence; // incremented each level change
2178         memexpandablearray_t array;
2179         skinframe_t *hash[SKINFRAME_HASH];
2180 }
2181 r_skinframe_t;
2182 r_skinframe_t r_skinframe;
2183
2184 void R_SkinFrame_PrepareForPurge(void)
2185 {
2186         r_skinframe.loadsequence++;
2187         // wrap it without hitting zero
2188         if (r_skinframe.loadsequence >= 200)
2189                 r_skinframe.loadsequence = 1;
2190 }
2191
2192 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2193 {
2194         if (!skinframe)
2195                 return;
2196         // mark the skinframe as used for the purging code
2197         skinframe->loadsequence = r_skinframe.loadsequence;
2198 }
2199
2200 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2201 {
2202         if (s == NULL)
2203                 return;
2204         if (s->merged == s->base)
2205                 s->merged = NULL;
2206         R_PurgeTexture(s->stain); s->stain = NULL;
2207         R_PurgeTexture(s->merged); s->merged = NULL;
2208         R_PurgeTexture(s->base); s->base = NULL;
2209         R_PurgeTexture(s->pants); s->pants = NULL;
2210         R_PurgeTexture(s->shirt); s->shirt = NULL;
2211         R_PurgeTexture(s->nmap); s->nmap = NULL;
2212         R_PurgeTexture(s->gloss); s->gloss = NULL;
2213         R_PurgeTexture(s->glow); s->glow = NULL;
2214         R_PurgeTexture(s->fog); s->fog = NULL;
2215         R_PurgeTexture(s->reflect); s->reflect = NULL;
2216         s->loadsequence = 0;
2217 }
2218
2219 void R_SkinFrame_Purge(void)
2220 {
2221         int i;
2222         skinframe_t *s;
2223         for (i = 0;i < SKINFRAME_HASH;i++)
2224         {
2225                 for (s = r_skinframe.hash[i];s;s = s->next)
2226                 {
2227                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2228                                 R_SkinFrame_PurgeSkinFrame(s);
2229                 }
2230         }
2231 }
2232
2233 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2234         skinframe_t *item;
2235         char basename[MAX_QPATH];
2236
2237         Image_StripImageExtension(name, basename, sizeof(basename));
2238
2239         if( last == NULL ) {
2240                 int hashindex;
2241                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2242                 item = r_skinframe.hash[hashindex];
2243         } else {
2244                 item = last->next;
2245         }
2246
2247         // linearly search through the hash bucket
2248         for( ; item ; item = item->next ) {
2249                 if( !strcmp( item->basename, basename ) ) {
2250                         return item;
2251                 }
2252         }
2253         return NULL;
2254 }
2255
2256 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2257 {
2258         skinframe_t *item;
2259         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2260         int hashindex;
2261         char basename[MAX_QPATH];
2262
2263         Image_StripImageExtension(name, basename, sizeof(basename));
2264
2265         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2266         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2267                 if (!strcmp(item->basename, basename) &&
2268                         item->textureflags == compareflags &&
2269                         item->comparewidth == comparewidth &&
2270                         item->compareheight == compareheight &&
2271                         item->comparecrc == comparecrc)
2272                         break;
2273
2274         if (!item)
2275         {
2276                 if (!add)
2277                         return NULL;
2278                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2279                 memset(item, 0, sizeof(*item));
2280                 strlcpy(item->basename, basename, sizeof(item->basename));
2281                 item->textureflags = compareflags;
2282                 item->comparewidth = comparewidth;
2283                 item->compareheight = compareheight;
2284                 item->comparecrc = comparecrc;
2285                 item->next = r_skinframe.hash[hashindex];
2286                 r_skinframe.hash[hashindex] = item;
2287         }
2288         else if (textureflags & TEXF_FORCE_RELOAD)
2289                 R_SkinFrame_PurgeSkinFrame(item);
2290
2291         R_SkinFrame_MarkUsed(item);
2292         return item;
2293 }
2294
2295 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2296         { \
2297                 unsigned long long avgcolor[5], wsum; \
2298                 int pix, comp, w; \
2299                 avgcolor[0] = 0; \
2300                 avgcolor[1] = 0; \
2301                 avgcolor[2] = 0; \
2302                 avgcolor[3] = 0; \
2303                 avgcolor[4] = 0; \
2304                 wsum = 0; \
2305                 for(pix = 0; pix < cnt; ++pix) \
2306                 { \
2307                         w = 0; \
2308                         for(comp = 0; comp < 3; ++comp) \
2309                                 w += getpixel; \
2310                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2311                         { \
2312                                 ++wsum; \
2313                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2314                                 w = getpixel; \
2315                                 for(comp = 0; comp < 3; ++comp) \
2316                                         avgcolor[comp] += getpixel * w; \
2317                                 avgcolor[3] += w; \
2318                         } \
2319                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2320                         avgcolor[4] += getpixel; \
2321                 } \
2322                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2323                         avgcolor[3] = 1; \
2324                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2325                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2326                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2327                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2328         }
2329
2330 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2331 {
2332         skinframe_t *skinframe;
2333
2334         if (cls.state == ca_dedicated)
2335                 return NULL;
2336
2337         // return an existing skinframe if already loaded
2338         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2339         if (skinframe && skinframe->base)
2340                 return skinframe;
2341
2342         // if the skinframe doesn't exist this will create it
2343         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2344 }
2345
2346 extern cvar_t gl_picmip;
2347 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2348 {
2349         int j;
2350         unsigned char *pixels;
2351         unsigned char *bumppixels;
2352         unsigned char *basepixels = NULL;
2353         int basepixels_width = 0;
2354         int basepixels_height = 0;
2355         rtexture_t *ddsbase = NULL;
2356         qboolean ddshasalpha = false;
2357         float ddsavgcolor[4];
2358         char basename[MAX_QPATH];
2359         int miplevel = R_PicmipForFlags(textureflags);
2360         int savemiplevel = miplevel;
2361         int mymiplevel;
2362         char vabuf[1024];
2363
2364         if (cls.state == ca_dedicated)
2365                 return NULL;
2366
2367         Image_StripImageExtension(name, basename, sizeof(basename));
2368
2369         // check for DDS texture file first
2370         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2371         {
2372                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2373                 if (basepixels == NULL && fallbacknotexture)
2374                         basepixels = Image_GenerateNoTexture();
2375                 if (basepixels == NULL)
2376                         return NULL;
2377         }
2378
2379         // FIXME handle miplevel
2380
2381         if (developer_loading.integer)
2382                 Con_Printf("loading skin \"%s\"\n", name);
2383
2384         // we've got some pixels to store, so really allocate this new texture now
2385         if (!skinframe)
2386                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2387         textureflags &= ~TEXF_FORCE_RELOAD;
2388         skinframe->stain = NULL;
2389         skinframe->merged = NULL;
2390         skinframe->base = NULL;
2391         skinframe->pants = NULL;
2392         skinframe->shirt = NULL;
2393         skinframe->nmap = NULL;
2394         skinframe->gloss = NULL;
2395         skinframe->glow = NULL;
2396         skinframe->fog = NULL;
2397         skinframe->reflect = NULL;
2398         skinframe->hasalpha = false;
2399         // we could store the q2animname here too
2400
2401         if (ddsbase)
2402         {
2403                 skinframe->base = ddsbase;
2404                 skinframe->hasalpha = ddshasalpha;
2405                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2406                 if (r_loadfog && skinframe->hasalpha)
2407                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2408                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2409         }
2410         else
2411         {
2412                 basepixels_width = image_width;
2413                 basepixels_height = image_height;
2414                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2415                 if (textureflags & TEXF_ALPHA)
2416                 {
2417                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2418                         {
2419                                 if (basepixels[j] < 255)
2420                                 {
2421                                         skinframe->hasalpha = true;
2422                                         break;
2423                                 }
2424                         }
2425                         if (r_loadfog && skinframe->hasalpha)
2426                         {
2427                                 // has transparent pixels
2428                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2429                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2430                                 {
2431                                         pixels[j+0] = 255;
2432                                         pixels[j+1] = 255;
2433                                         pixels[j+2] = 255;
2434                                         pixels[j+3] = basepixels[j+3];
2435                                 }
2436                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2437                                 Mem_Free(pixels);
2438                         }
2439                 }
2440                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2441 #ifndef USE_GLES2
2442                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2443                 if (r_savedds && skinframe->base)
2444                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2445                 if (r_savedds && skinframe->fog)
2446                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2447 #endif
2448         }
2449
2450         if (r_loaddds)
2451         {
2452                 mymiplevel = savemiplevel;
2453                 if (r_loadnormalmap)
2454                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2455                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2456                 if (r_loadgloss)
2457                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2458                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2459                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2460                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2461         }
2462
2463         // _norm is the name used by tenebrae and has been adopted as standard
2464         if (r_loadnormalmap && skinframe->nmap == NULL)
2465         {
2466                 mymiplevel = savemiplevel;
2467                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2468                 {
2469                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2470                         Mem_Free(pixels);
2471                         pixels = NULL;
2472                 }
2473                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2474                 {
2475                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2476                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2477                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2478                         Mem_Free(pixels);
2479                         Mem_Free(bumppixels);
2480                 }
2481                 else if (r_shadow_bumpscale_basetexture.value > 0)
2482                 {
2483                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2484                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2485                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2486                         Mem_Free(pixels);
2487                 }
2488 #ifndef USE_GLES2
2489                 if (r_savedds && skinframe->nmap)
2490                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2491 #endif
2492         }
2493
2494         // _luma is supported only for tenebrae compatibility
2495         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2496         // _glow is the preferred name
2497         mymiplevel = savemiplevel;
2498         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s.blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2499         {
2500                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2501 #ifndef USE_GLES2
2502                 if (r_savedds && skinframe->glow)
2503                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2504 #endif
2505                 Mem_Free(pixels);pixels = NULL;
2506         }
2507
2508         mymiplevel = savemiplevel;
2509         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2510         {
2511                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2512 #ifndef USE_GLES2
2513                 if (r_savedds && skinframe->gloss)
2514                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2515 #endif
2516                 Mem_Free(pixels);
2517                 pixels = NULL;
2518         }
2519
2520         mymiplevel = savemiplevel;
2521         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2522         {
2523                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2524 #ifndef USE_GLES2
2525                 if (r_savedds && skinframe->pants)
2526                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2527 #endif
2528                 Mem_Free(pixels);
2529                 pixels = NULL;
2530         }
2531
2532         mymiplevel = savemiplevel;
2533         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2534         {
2535                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2536 #ifndef USE_GLES2
2537                 if (r_savedds && skinframe->shirt)
2538                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2539 #endif
2540                 Mem_Free(pixels);
2541                 pixels = NULL;
2542         }
2543
2544         mymiplevel = savemiplevel;
2545         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2546         {
2547                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2548 #ifndef USE_GLES2
2549                 if (r_savedds && skinframe->reflect)
2550                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2551 #endif
2552                 Mem_Free(pixels);
2553                 pixels = NULL;
2554         }
2555
2556         if (basepixels)
2557                 Mem_Free(basepixels);
2558
2559         return skinframe;
2560 }
2561
2562 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2563 {
2564         int i;
2565         skinframe_t *skinframe;
2566         char vabuf[1024];
2567
2568         if (cls.state == ca_dedicated)
2569                 return NULL;
2570
2571         // if already loaded just return it, otherwise make a new skinframe
2572         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2573         if (skinframe->base)
2574                 return skinframe;
2575         textureflags &= ~TEXF_FORCE_RELOAD;
2576
2577         skinframe->stain = NULL;
2578         skinframe->merged = NULL;
2579         skinframe->base = NULL;
2580         skinframe->pants = NULL;
2581         skinframe->shirt = NULL;
2582         skinframe->nmap = NULL;
2583         skinframe->gloss = NULL;
2584         skinframe->glow = NULL;
2585         skinframe->fog = NULL;
2586         skinframe->reflect = NULL;
2587         skinframe->hasalpha = false;
2588
2589         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2590         if (!skindata)
2591                 return NULL;
2592
2593         if (developer_loading.integer)
2594                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2595
2596         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2597         {
2598                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2599                 unsigned char *b = a + width * height * 4;
2600                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2601                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2602                 Mem_Free(a);
2603         }
2604         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2605         if (textureflags & TEXF_ALPHA)
2606         {
2607                 for (i = 3;i < width * height * 4;i += 4)
2608                 {
2609                         if (skindata[i] < 255)
2610                         {
2611                                 skinframe->hasalpha = true;
2612                                 break;
2613                         }
2614                 }
2615                 if (r_loadfog && skinframe->hasalpha)
2616                 {
2617                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2618                         memcpy(fogpixels, skindata, width * height * 4);
2619                         for (i = 0;i < width * height * 4;i += 4)
2620                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2621                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2622                         Mem_Free(fogpixels);
2623                 }
2624         }
2625
2626         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2627         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2628
2629         return skinframe;
2630 }
2631
2632 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2633 {
2634         int i;
2635         int featuresmask;
2636         skinframe_t *skinframe;
2637
2638         if (cls.state == ca_dedicated)
2639                 return NULL;
2640
2641         // if already loaded just return it, otherwise make a new skinframe
2642         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2643         if (skinframe->base)
2644                 return skinframe;
2645         //textureflags &= ~TEXF_FORCE_RELOAD;
2646
2647         skinframe->stain = NULL;
2648         skinframe->merged = NULL;
2649         skinframe->base = NULL;
2650         skinframe->pants = NULL;
2651         skinframe->shirt = NULL;
2652         skinframe->nmap = NULL;
2653         skinframe->gloss = NULL;
2654         skinframe->glow = NULL;
2655         skinframe->fog = NULL;
2656         skinframe->reflect = NULL;
2657         skinframe->hasalpha = false;
2658
2659         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2660         if (!skindata)
2661                 return NULL;
2662
2663         if (developer_loading.integer)
2664                 Con_Printf("loading quake skin \"%s\"\n", name);
2665
2666         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2667         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2668         memcpy(skinframe->qpixels, skindata, width*height);
2669         skinframe->qwidth = width;
2670         skinframe->qheight = height;
2671
2672         featuresmask = 0;
2673         for (i = 0;i < width * height;i++)
2674                 featuresmask |= palette_featureflags[skindata[i]];
2675
2676         skinframe->hasalpha = false;
2677         // fence textures
2678         if (name[0] == '{')
2679                 skinframe->hasalpha = true;
2680         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2681         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2682         skinframe->qgeneratemerged = true;
2683         skinframe->qgeneratebase = skinframe->qhascolormapping;
2684         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2685
2686         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2687         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2688
2689         return skinframe;
2690 }
2691
2692 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2693 {
2694         int width;
2695         int height;
2696         unsigned char *skindata;
2697         char vabuf[1024];
2698
2699         if (!skinframe->qpixels)
2700                 return;
2701
2702         if (!skinframe->qhascolormapping)
2703                 colormapped = false;
2704
2705         if (colormapped)
2706         {
2707                 if (!skinframe->qgeneratebase)
2708                         return;
2709         }
2710         else
2711         {
2712                 if (!skinframe->qgeneratemerged)
2713                         return;
2714         }
2715
2716         width = skinframe->qwidth;
2717         height = skinframe->qheight;
2718         skindata = skinframe->qpixels;
2719
2720         if (skinframe->qgeneratenmap)
2721         {
2722                 unsigned char *a, *b;
2723                 skinframe->qgeneratenmap = false;
2724                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2725                 b = a + width * height * 4;
2726                 // use either a custom palette or the quake palette
2727                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2728                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2729                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2730                 Mem_Free(a);
2731         }
2732
2733         if (skinframe->qgenerateglow)
2734         {
2735                 skinframe->qgenerateglow = false;
2736                 if (skinframe->hasalpha) // fence textures
2737                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2738                 else
2739                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2740         }
2741
2742         if (colormapped)
2743         {
2744                 skinframe->qgeneratebase = false;
2745                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2746                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2747                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2748         }
2749         else
2750         {
2751                 skinframe->qgeneratemerged = false;
2752                 if (skinframe->hasalpha) // fence textures
2753                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2754                 else
2755                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2756         }
2757
2758         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2759         {
2760                 Mem_Free(skinframe->qpixels);
2761                 skinframe->qpixels = NULL;
2762         }
2763 }
2764
2765 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2766 {
2767         int i;
2768         skinframe_t *skinframe;
2769         char vabuf[1024];
2770
2771         if (cls.state == ca_dedicated)
2772                 return NULL;
2773
2774         // if already loaded just return it, otherwise make a new skinframe
2775         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2776         if (skinframe->base)
2777                 return skinframe;
2778         textureflags &= ~TEXF_FORCE_RELOAD;
2779
2780         skinframe->stain = NULL;
2781         skinframe->merged = NULL;
2782         skinframe->base = NULL;
2783         skinframe->pants = NULL;
2784         skinframe->shirt = NULL;
2785         skinframe->nmap = NULL;
2786         skinframe->gloss = NULL;
2787         skinframe->glow = NULL;
2788         skinframe->fog = NULL;
2789         skinframe->reflect = NULL;
2790         skinframe->hasalpha = false;
2791
2792         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2793         if (!skindata)
2794                 return NULL;
2795
2796         if (developer_loading.integer)
2797                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2798
2799         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2800         if ((textureflags & TEXF_ALPHA) && alphapalette)
2801         {
2802                 for (i = 0;i < width * height;i++)
2803                 {
2804                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2805                         {
2806                                 skinframe->hasalpha = true;
2807                                 break;
2808                         }
2809                 }
2810                 if (r_loadfog && skinframe->hasalpha)
2811                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2812         }
2813
2814         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2815         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2816
2817         return skinframe;
2818 }
2819
2820 skinframe_t *R_SkinFrame_LoadMissing(void)
2821 {
2822         skinframe_t *skinframe;
2823
2824         if (cls.state == ca_dedicated)
2825                 return NULL;
2826
2827         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2828         skinframe->stain = NULL;
2829         skinframe->merged = NULL;
2830         skinframe->base = NULL;
2831         skinframe->pants = NULL;
2832         skinframe->shirt = NULL;
2833         skinframe->nmap = NULL;
2834         skinframe->gloss = NULL;
2835         skinframe->glow = NULL;
2836         skinframe->fog = NULL;
2837         skinframe->reflect = NULL;
2838         skinframe->hasalpha = false;
2839
2840         skinframe->avgcolor[0] = rand() / RAND_MAX;
2841         skinframe->avgcolor[1] = rand() / RAND_MAX;
2842         skinframe->avgcolor[2] = rand() / RAND_MAX;
2843         skinframe->avgcolor[3] = 1;
2844
2845         return skinframe;
2846 }
2847
2848 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2849 {
2850         int x, y;
2851         static unsigned char pix[16][16][4];
2852
2853         if (cls.state == ca_dedicated)
2854                 return NULL;
2855
2856         // this makes a light grey/dark grey checkerboard texture
2857         if (!pix[0][0][3])
2858         {
2859                 for (y = 0; y < 16; y++)
2860                 {
2861                         for (x = 0; x < 16; x++)
2862                         {
2863                                 if ((y < 8) ^ (x < 8))
2864                                 {
2865                                         pix[y][x][0] = 128;
2866                                         pix[y][x][1] = 128;
2867                                         pix[y][x][2] = 128;
2868                                         pix[y][x][3] = 255;
2869                                 }
2870                                 else
2871                                 {
2872                                         pix[y][x][0] = 64;
2873                                         pix[y][x][1] = 64;
2874                                         pix[y][x][2] = 64;
2875                                         pix[y][x][3] = 255;
2876                                 }
2877                         }
2878                 }
2879         }
2880
2881         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2882 }
2883
2884 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2885 {
2886         skinframe_t *skinframe;
2887         if (cls.state == ca_dedicated)
2888                 return NULL;
2889         // if already loaded just return it, otherwise make a new skinframe
2890         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2891         if (skinframe->base)
2892                 return skinframe;
2893         textureflags &= ~TEXF_FORCE_RELOAD;
2894         skinframe->stain = NULL;
2895         skinframe->merged = NULL;
2896         skinframe->base = NULL;
2897         skinframe->pants = NULL;
2898         skinframe->shirt = NULL;
2899         skinframe->nmap = NULL;
2900         skinframe->gloss = NULL;
2901         skinframe->glow = NULL;
2902         skinframe->fog = NULL;
2903         skinframe->reflect = NULL;
2904         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2905         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2906         if (!tex)
2907                 return NULL;
2908         if (developer_loading.integer)
2909                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2910         skinframe->base = skinframe->merged = tex;
2911         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2912         return skinframe;
2913 }
2914
2915 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2916 typedef struct suffixinfo_s
2917 {
2918         const char *suffix;
2919         qboolean flipx, flipy, flipdiagonal;
2920 }
2921 suffixinfo_t;
2922 static suffixinfo_t suffix[3][6] =
2923 {
2924         {
2925                 {"px",   false, false, false},
2926                 {"nx",   false, false, false},
2927                 {"py",   false, false, false},
2928                 {"ny",   false, false, false},
2929                 {"pz",   false, false, false},
2930                 {"nz",   false, false, false}
2931         },
2932         {
2933                 {"posx", false, false, false},
2934                 {"negx", false, false, false},
2935                 {"posy", false, false, false},
2936                 {"negy", false, false, false},
2937                 {"posz", false, false, false},
2938                 {"negz", false, false, false}
2939         },
2940         {
2941                 {"rt",    true, false,  true},
2942                 {"lf",   false,  true,  true},
2943                 {"ft",    true,  true, false},
2944                 {"bk",   false, false, false},
2945                 {"up",    true, false,  true},
2946                 {"dn",    true, false,  true}
2947         }
2948 };
2949
2950 static int componentorder[4] = {0, 1, 2, 3};
2951
2952 static rtexture_t *R_LoadCubemap(const char *basename)
2953 {
2954         int i, j, cubemapsize, forcefilter;
2955         unsigned char *cubemappixels, *image_buffer;
2956         rtexture_t *cubemaptexture;
2957         char name[256];
2958
2959         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2960         forcefilter = TEXF_FORCELINEAR;
2961         if (basename && basename[0] == '!')
2962         {
2963                 basename++;
2964                 forcefilter = TEXF_FORCENEAREST;
2965         }
2966         // must start 0 so the first loadimagepixels has no requested width/height
2967         cubemapsize = 0;
2968         cubemappixels = NULL;
2969         cubemaptexture = NULL;
2970         // keep trying different suffix groups (posx, px, rt) until one loads
2971         for (j = 0;j < 3 && !cubemappixels;j++)
2972         {
2973                 // load the 6 images in the suffix group
2974                 for (i = 0;i < 6;i++)
2975                 {
2976                         // generate an image name based on the base and and suffix
2977                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2978                         // load it
2979                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2980                         {
2981                                 // an image loaded, make sure width and height are equal
2982                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2983                                 {
2984                                         // if this is the first image to load successfully, allocate the cubemap memory
2985                                         if (!cubemappixels && image_width >= 1)
2986                                         {
2987                                                 cubemapsize = image_width;
2988                                                 // note this clears to black, so unavailable sides are black
2989                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2990                                         }
2991                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2992                                         if (cubemappixels)
2993                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2994                                 }
2995                                 else
2996                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2997                                 // free the image
2998                                 Mem_Free(image_buffer);
2999                         }
3000                 }
3001         }
3002         // if a cubemap loaded, upload it
3003         if (cubemappixels)
3004         {
3005                 if (developer_loading.integer)
3006                         Con_Printf("loading cubemap \"%s\"\n", basename);
3007
3008                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | forcefilter | TEXF_CLAMP, -1, NULL);
3009                 Mem_Free(cubemappixels);
3010         }
3011         else
3012         {
3013                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3014                 if (developer_loading.integer)
3015                 {
3016                         Con_Printf("(tried tried images ");
3017                         for (j = 0;j < 3;j++)
3018                                 for (i = 0;i < 6;i++)
3019                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3020                         Con_Print(" and was unable to find any of them).\n");
3021                 }
3022         }
3023         return cubemaptexture;
3024 }
3025
3026 rtexture_t *R_GetCubemap(const char *basename)
3027 {
3028         int i;
3029         for (i = 0;i < r_texture_numcubemaps;i++)
3030                 if (r_texture_cubemaps[i] != NULL)
3031                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
3032                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
3033         if (i >= MAX_CUBEMAPS || !r_main_mempool)
3034                 return r_texture_whitecube;
3035         r_texture_numcubemaps++;
3036         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
3037         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
3038         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
3039         return r_texture_cubemaps[i]->texture;
3040 }
3041
3042 static void R_Main_FreeViewCache(void)
3043 {
3044         if (r_refdef.viewcache.entityvisible)
3045                 Mem_Free(r_refdef.viewcache.entityvisible);
3046         if (r_refdef.viewcache.world_pvsbits)
3047                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3048         if (r_refdef.viewcache.world_leafvisible)
3049                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3050         if (r_refdef.viewcache.world_surfacevisible)
3051                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3052         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3053 }
3054
3055 static void R_Main_ResizeViewCache(void)
3056 {
3057         int numentities = r_refdef.scene.numentities;
3058         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3059         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3060         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3061         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3062         if (r_refdef.viewcache.maxentities < numentities)
3063         {
3064                 r_refdef.viewcache.maxentities = numentities;
3065                 if (r_refdef.viewcache.entityvisible)
3066                         Mem_Free(r_refdef.viewcache.entityvisible);
3067                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3068         }
3069         if (r_refdef.viewcache.world_numclusters != numclusters)
3070         {
3071                 r_refdef.viewcache.world_numclusters = numclusters;
3072                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3073                 if (r_refdef.viewcache.world_pvsbits)
3074                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3075                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3076         }
3077         if (r_refdef.viewcache.world_numleafs != numleafs)
3078         {
3079                 r_refdef.viewcache.world_numleafs = numleafs;
3080                 if (r_refdef.viewcache.world_leafvisible)
3081                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3082                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3083         }
3084         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3085         {
3086                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3087                 if (r_refdef.viewcache.world_surfacevisible)
3088                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3089                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3090         }
3091 }
3092
3093 extern rtexture_t *loadingscreentexture;
3094 static void gl_main_start(void)
3095 {
3096         loadingscreentexture = NULL;
3097         r_texture_blanknormalmap = NULL;
3098         r_texture_white = NULL;
3099         r_texture_grey128 = NULL;
3100         r_texture_black = NULL;
3101         r_texture_whitecube = NULL;
3102         r_texture_normalizationcube = NULL;
3103         r_texture_fogattenuation = NULL;
3104         r_texture_fogheighttexture = NULL;
3105         r_texture_gammaramps = NULL;
3106         r_texture_numcubemaps = 0;
3107         r_uniformbufferalignment = 32;
3108
3109         r_loaddds = r_texture_dds_load.integer != 0;
3110         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3111
3112         switch(vid.renderpath)
3113         {
3114         case RENDERPATH_GL32:
3115         case RENDERPATH_GLES2:
3116                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3117                 Cvar_SetValueQuick(&gl_combine, 1);
3118                 Cvar_SetValueQuick(&r_glsl, 1);
3119                 r_loadnormalmap = true;
3120                 r_loadgloss = true;
3121                 r_loadfog = false;
3122 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3123                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3124 #endif
3125                 break;
3126         }
3127
3128         R_AnimCache_Free();
3129         R_FrameData_Reset();
3130         R_BufferData_Reset();
3131
3132         r_numqueries = 0;
3133         r_maxqueries = 0;
3134         memset(r_queries, 0, sizeof(r_queries));
3135
3136         r_qwskincache = NULL;
3137         r_qwskincache_size = 0;
3138
3139         // due to caching of texture_t references, the collision cache must be reset
3140         Collision_Cache_Reset(true);
3141
3142         // set up r_skinframe loading system for textures
3143         memset(&r_skinframe, 0, sizeof(r_skinframe));
3144         r_skinframe.loadsequence = 1;
3145         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3146
3147         r_main_texturepool = R_AllocTexturePool();
3148         R_BuildBlankTextures();
3149         R_BuildNoTexture();
3150         R_BuildWhiteCube();
3151         R_BuildNormalizationCube();
3152         r_texture_fogattenuation = NULL;
3153         r_texture_fogheighttexture = NULL;
3154         r_texture_gammaramps = NULL;
3155         //r_texture_fogintensity = NULL;
3156         memset(&r_fb, 0, sizeof(r_fb));
3157         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3158         r_glsl_permutation = NULL;
3159         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3160         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3161         memset(&r_svbsp, 0, sizeof (r_svbsp));
3162
3163         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3164         r_texture_numcubemaps = 0;
3165
3166         r_refdef.fogmasktable_density = 0;
3167
3168 #ifdef __ANDROID__
3169         // For Steelstorm Android
3170         // FIXME CACHE the program and reload
3171         // FIXME see possible combinations for SS:BR android
3172         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3173         R_SetupShader_SetPermutationGLSL(0, 12);
3174         R_SetupShader_SetPermutationGLSL(0, 13);
3175         R_SetupShader_SetPermutationGLSL(0, 8388621);
3176         R_SetupShader_SetPermutationGLSL(3, 0);
3177         R_SetupShader_SetPermutationGLSL(3, 2048);
3178         R_SetupShader_SetPermutationGLSL(5, 0);
3179         R_SetupShader_SetPermutationGLSL(5, 2);
3180         R_SetupShader_SetPermutationGLSL(5, 2048);
3181         R_SetupShader_SetPermutationGLSL(5, 8388608);
3182         R_SetupShader_SetPermutationGLSL(11, 1);
3183         R_SetupShader_SetPermutationGLSL(11, 2049);
3184         R_SetupShader_SetPermutationGLSL(11, 8193);
3185         R_SetupShader_SetPermutationGLSL(11, 10241);
3186         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3187 #endif
3188 }
3189
3190 extern unsigned int r_shadow_occlusion_buf;
3191
3192 static void gl_main_shutdown(void)
3193 {
3194         R_RenderTarget_FreeUnused(true);
3195         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3196         R_AnimCache_Free();
3197         R_FrameData_Reset();
3198         R_BufferData_Reset();
3199
3200         R_Main_FreeViewCache();
3201
3202         switch(vid.renderpath)
3203         {
3204         case RENDERPATH_GL32:
3205         case RENDERPATH_GLES2:
3206 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3207                 if (r_maxqueries)
3208                         qglDeleteQueries(r_maxqueries, r_queries);
3209 #endif
3210                 break;
3211         }
3212         r_shadow_occlusion_buf = 0;
3213         r_numqueries = 0;
3214         r_maxqueries = 0;
3215         memset(r_queries, 0, sizeof(r_queries));
3216
3217         r_qwskincache = NULL;
3218         r_qwskincache_size = 0;
3219
3220         // clear out the r_skinframe state
3221         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3222         memset(&r_skinframe, 0, sizeof(r_skinframe));
3223
3224         if (r_svbsp.nodes)
3225                 Mem_Free(r_svbsp.nodes);
3226         memset(&r_svbsp, 0, sizeof (r_svbsp));
3227         R_FreeTexturePool(&r_main_texturepool);
3228         loadingscreentexture = NULL;
3229         r_texture_blanknormalmap = NULL;
3230         r_texture_white = NULL;
3231         r_texture_grey128 = NULL;
3232         r_texture_black = NULL;
3233         r_texture_whitecube = NULL;
3234         r_texture_normalizationcube = NULL;
3235         r_texture_fogattenuation = NULL;
3236         r_texture_fogheighttexture = NULL;
3237         r_texture_gammaramps = NULL;
3238         r_texture_numcubemaps = 0;
3239         //r_texture_fogintensity = NULL;
3240         memset(&r_fb, 0, sizeof(r_fb));
3241         R_GLSL_Restart_f(&cmd_client);
3242
3243         r_glsl_permutation = NULL;
3244         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3245         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3246 }
3247
3248 static void gl_main_newmap(void)
3249 {
3250         // FIXME: move this code to client
3251         char *entities, entname[MAX_QPATH];
3252         if (r_qwskincache)
3253                 Mem_Free(r_qwskincache);
3254         r_qwskincache = NULL;
3255         r_qwskincache_size = 0;
3256         if (cl.worldmodel)
3257         {
3258                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3259                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3260                 {
3261                         CL_ParseEntityLump(entities);
3262                         Mem_Free(entities);
3263                         return;
3264                 }
3265                 if (cl.worldmodel->brush.entities)
3266                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3267         }
3268         R_Main_FreeViewCache();
3269
3270         R_FrameData_Reset();
3271         R_BufferData_Reset();
3272 }
3273
3274 void GL_Main_Init(void)
3275 {
3276         int i;
3277         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3278         R_InitShaderModeInfo();
3279
3280         Cmd_AddCommand(CMD_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3281         Cmd_AddCommand(CMD_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3282         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3283         if (gamemode == GAME_NEHAHRA)
3284         {
3285                 Cvar_RegisterVariable (&gl_fogenable);
3286                 Cvar_RegisterVariable (&gl_fogdensity);
3287                 Cvar_RegisterVariable (&gl_fogred);
3288                 Cvar_RegisterVariable (&gl_foggreen);
3289                 Cvar_RegisterVariable (&gl_fogblue);
3290                 Cvar_RegisterVariable (&gl_fogstart);
3291                 Cvar_RegisterVariable (&gl_fogend);
3292                 Cvar_RegisterVariable (&gl_skyclip);
3293         }
3294         Cvar_RegisterVariable(&r_motionblur);
3295         Cvar_RegisterVariable(&r_damageblur);
3296         Cvar_RegisterVariable(&r_motionblur_averaging);
3297         Cvar_RegisterVariable(&r_motionblur_randomize);
3298         Cvar_RegisterVariable(&r_motionblur_minblur);
3299         Cvar_RegisterVariable(&r_motionblur_maxblur);
3300         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3301         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3302         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3303         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3304         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3305         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3306         Cvar_RegisterVariable(&r_depthfirst);
3307         Cvar_RegisterVariable(&r_useinfinitefarclip);
3308         Cvar_RegisterVariable(&r_farclip_base);
3309         Cvar_RegisterVariable(&r_farclip_world);
3310         Cvar_RegisterVariable(&r_nearclip);
3311         Cvar_RegisterVariable(&r_deformvertexes);
3312         Cvar_RegisterVariable(&r_transparent);
3313         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3314         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3315         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3316         Cvar_RegisterVariable(&r_showoverdraw);
3317         Cvar_RegisterVariable(&r_showbboxes);
3318         Cvar_RegisterVariable(&r_showbboxes_client);
3319         Cvar_RegisterVariable(&r_showsurfaces);
3320         Cvar_RegisterVariable(&r_showtris);
3321         Cvar_RegisterVariable(&r_shownormals);
3322         Cvar_RegisterVariable(&r_showlighting);
3323         Cvar_RegisterVariable(&r_showcollisionbrushes);
3324         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3325         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3326         Cvar_RegisterVariable(&r_showdisabledepthtest);
3327         Cvar_RegisterVariable(&r_showspriteedges);
3328         Cvar_RegisterVariable(&r_showparticleedges);
3329         Cvar_RegisterVariable(&r_drawportals);
3330         Cvar_RegisterVariable(&r_drawentities);
3331         Cvar_RegisterVariable(&r_draw2d);
3332         Cvar_RegisterVariable(&r_drawworld);
3333         Cvar_RegisterVariable(&r_cullentities_trace);
3334         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3335         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3336         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3337         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3338         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3339         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3340         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3341         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3342         Cvar_RegisterVariable(&r_sortentities);
3343         Cvar_RegisterVariable(&r_drawviewmodel);
3344         Cvar_RegisterVariable(&r_drawexteriormodel);
3345         Cvar_RegisterVariable(&r_speeds);
3346         Cvar_RegisterVariable(&r_fullbrights);
3347         Cvar_RegisterVariable(&r_wateralpha);
3348         Cvar_RegisterVariable(&r_dynamic);
3349         Cvar_RegisterVariable(&r_fullbright_directed);
3350         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3351         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3352         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3353         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3354         Cvar_RegisterVariable(&r_fullbright);
3355         Cvar_RegisterVariable(&r_shadows);
3356         Cvar_RegisterVariable(&r_shadows_darken);
3357         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3358         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3359         Cvar_RegisterVariable(&r_shadows_throwdistance);
3360         Cvar_RegisterVariable(&r_shadows_throwdirection);
3361         Cvar_RegisterVariable(&r_shadows_focus);
3362         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3363         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3364         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3365         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3366         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3367         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3368         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3369         Cvar_RegisterVariable(&r_fog_exp2);
3370         Cvar_RegisterVariable(&r_fog_clear);
3371         Cvar_RegisterVariable(&r_drawfog);
3372         Cvar_RegisterVariable(&r_transparentdepthmasking);
3373         Cvar_RegisterVariable(&r_transparent_sortmindist);
3374         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3375         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3376         Cvar_RegisterVariable(&r_texture_dds_load);
3377         Cvar_RegisterVariable(&r_texture_dds_save);
3378         Cvar_RegisterVariable(&r_textureunits);
3379         Cvar_RegisterVariable(&gl_combine);
3380         Cvar_RegisterVariable(&r_usedepthtextures);
3381         Cvar_RegisterVariable(&r_viewfbo);
3382         Cvar_RegisterVariable(&r_rendertarget_debug);
3383         Cvar_RegisterVariable(&r_viewscale);
3384         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3385         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3386         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3387         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3388         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3389         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3390         Cvar_RegisterVariable(&r_glsl);
3391         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3392         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3393         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3394         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3395         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3396         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3397         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3398         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3399         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3400         Cvar_RegisterVariable(&r_glsl_postprocess);
3401         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3402         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3403         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3404         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3405         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3406         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3407         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3408         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3409         Cvar_RegisterVariable(&r_celshading);
3410         Cvar_RegisterVariable(&r_celoutlines);
3411
3412         Cvar_RegisterVariable(&r_water);
3413         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3414         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3415         Cvar_RegisterVariable(&r_water_clippingplanebias);
3416         Cvar_RegisterVariable(&r_water_refractdistort);
3417         Cvar_RegisterVariable(&r_water_reflectdistort);
3418         Cvar_RegisterVariable(&r_water_scissormode);
3419         Cvar_RegisterVariable(&r_water_lowquality);
3420         Cvar_RegisterVariable(&r_water_hideplayer);
3421
3422         Cvar_RegisterVariable(&r_lerpsprites);
3423         Cvar_RegisterVariable(&r_lerpmodels);
3424         Cvar_RegisterVariable(&r_nolerp_list);
3425         Cvar_RegisterVariable(&r_lerplightstyles);
3426         Cvar_RegisterVariable(&r_waterscroll);
3427         Cvar_RegisterVariable(&r_bloom);
3428         Cvar_RegisterVariable(&r_colorfringe);
3429         Cvar_RegisterVariable(&r_bloom_colorscale);
3430         Cvar_RegisterVariable(&r_bloom_brighten);
3431         Cvar_RegisterVariable(&r_bloom_blur);
3432         Cvar_RegisterVariable(&r_bloom_resolution);
3433         Cvar_RegisterVariable(&r_bloom_colorexponent);
3434         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3435         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3436         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3437         Cvar_RegisterVariable(&r_hdr_glowintensity);
3438         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3439         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3440         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3441         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3442         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3443         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3444         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3445         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3446         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3447         Cvar_RegisterVariable(&developer_texturelogging);
3448         Cvar_RegisterVariable(&gl_lightmaps);
3449         Cvar_RegisterVariable(&r_test);
3450         Cvar_RegisterVariable(&r_batch_multidraw);
3451         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3452         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3453         Cvar_RegisterVariable(&r_glsl_skeletal);
3454         Cvar_RegisterVariable(&r_glsl_saturation);
3455         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3456         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3457         Cvar_RegisterVariable(&r_framedatasize);
3458         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3459                 Cvar_RegisterVariable(&r_buffermegs[i]);
3460         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3461         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3462                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3463 #ifdef DP_MOBILETOUCH
3464         // GLES devices have terrible depth precision in general, so...
3465         Cvar_SetValueQuick(&r_nearclip, 4);
3466         Cvar_SetValueQuick(&r_farclip_base, 4096);
3467         Cvar_SetValueQuick(&r_farclip_world, 0);
3468         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3469 #endif
3470         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3471 }
3472
3473 void Render_Init(void)
3474 {
3475         gl_backend_init();
3476         R_Textures_Init();
3477         GL_Main_Init();
3478         Font_Init();
3479         GL_Draw_Init();
3480         R_Shadow_Init();
3481         R_Sky_Init();
3482         GL_Surf_Init();
3483         Sbar_Init();
3484         R_Particles_Init();
3485         R_Explosion_Init();
3486         R_LightningBeams_Init();
3487         Mod_RenderInit();
3488 }
3489
3490 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3491 {
3492         int i;
3493         mplane_t *p;
3494         if (r_trippy.integer)
3495                 return false;
3496         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3497         {
3498                 p = r_refdef.view.frustum + i;
3499                 switch(p->signbits)
3500                 {
3501                 default:
3502                 case 0:
3503                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3504                                 return true;
3505                         break;
3506                 case 1:
3507                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3508                                 return true;
3509                         break;
3510                 case 2:
3511                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3512                                 return true;
3513                         break;
3514                 case 3:
3515                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3516                                 return true;
3517                         break;
3518                 case 4:
3519                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3520                                 return true;
3521                         break;
3522                 case 5:
3523                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3524                                 return true;
3525                         break;
3526                 case 6:
3527                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3528                                 return true;
3529                         break;
3530                 case 7:
3531                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3532                                 return true;
3533                         break;
3534                 }
3535         }
3536         return false;
3537 }
3538
3539 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3540 {
3541         int i;
3542         const mplane_t *p;
3543         if (r_trippy.integer)
3544                 return false;
3545         for (i = 0;i < numplanes;i++)
3546         {
3547                 p = planes + i;
3548                 switch(p->signbits)
3549                 {
3550                 default:
3551                 case 0:
3552                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3553                                 return true;
3554                         break;
3555                 case 1:
3556                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3557                                 return true;
3558                         break;
3559                 case 2:
3560                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3561                                 return true;
3562                         break;
3563                 case 3:
3564                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3565                                 return true;
3566                         break;
3567                 case 4:
3568                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3569                                 return true;
3570                         break;
3571                 case 5:
3572                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3573                                 return true;
3574                         break;
3575                 case 6:
3576                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3577                                 return true;
3578                         break;
3579                 case 7:
3580                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3581                                 return true;
3582                         break;
3583                 }
3584         }
3585         return false;
3586 }
3587
3588 //==================================================================================
3589
3590 // LadyHavoc: this stores temporary data used within the same frame
3591
3592 typedef struct r_framedata_mem_s
3593 {
3594         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3595         size_t size; // how much usable space
3596         size_t current; // how much space in use
3597         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3598         size_t wantedsize; // how much space was allocated
3599         unsigned char *data; // start of real data (16byte aligned)
3600 }
3601 r_framedata_mem_t;
3602
3603 static r_framedata_mem_t *r_framedata_mem;
3604
3605 void R_FrameData_Reset(void)
3606 {
3607         while (r_framedata_mem)
3608         {
3609                 r_framedata_mem_t *next = r_framedata_mem->purge;
3610                 Mem_Free(r_framedata_mem);
3611                 r_framedata_mem = next;
3612         }
3613 }
3614
3615 static void R_FrameData_Resize(qboolean mustgrow)
3616 {
3617         size_t wantedsize;
3618         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3619         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3620         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3621         {
3622                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3623                 newmem->wantedsize = wantedsize;
3624                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3625                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3626                 newmem->current = 0;
3627                 newmem->mark = 0;
3628                 newmem->purge = r_framedata_mem;
3629                 r_framedata_mem = newmem;
3630         }
3631 }
3632
3633 void R_FrameData_NewFrame(void)
3634 {
3635         R_FrameData_Resize(false);
3636         if (!r_framedata_mem)
3637                 return;
3638         // if we ran out of space on the last frame, free the old memory now
3639         while (r_framedata_mem->purge)
3640         {
3641                 // repeatedly remove the second item in the list, leaving only head
3642                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3643                 Mem_Free(r_framedata_mem->purge);
3644                 r_framedata_mem->purge = next;
3645         }
3646         // reset the current mem pointer
3647         r_framedata_mem->current = 0;
3648         r_framedata_mem->mark = 0;
3649 }
3650
3651 void *R_FrameData_Alloc(size_t size)
3652 {
3653         void *data;
3654         float newvalue;
3655
3656         // align to 16 byte boundary - the data pointer is already aligned, so we
3657         // only need to ensure the size of every allocation is also aligned
3658         size = (size + 15) & ~15;
3659
3660         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3661         {
3662                 // emergency - we ran out of space, allocate more memory
3663                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3664                 newvalue = r_framedatasize.value * 2.0f;
3665                 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3666                 if (sizeof(size_t) >= 8)
3667                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3668                 else
3669                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3670                 // this might not be a growing it, but we'll allocate another buffer every time
3671                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3672                 R_FrameData_Resize(true);
3673         }
3674
3675         data = r_framedata_mem->data + r_framedata_mem->current;
3676         r_framedata_mem->current += size;
3677
3678         // count the usage for stats
3679         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3680         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3681
3682         return (void *)data;
3683 }
3684
3685 void *R_FrameData_Store(size_t size, void *data)
3686 {
3687         void *d = R_FrameData_Alloc(size);
3688         if (d && data)
3689                 memcpy(d, data, size);
3690         return d;
3691 }
3692
3693 void R_FrameData_SetMark(void)
3694 {
3695         if (!r_framedata_mem)
3696                 return;
3697         r_framedata_mem->mark = r_framedata_mem->current;
3698 }
3699
3700 void R_FrameData_ReturnToMark(void)
3701 {
3702         if (!r_framedata_mem)
3703                 return;
3704         r_framedata_mem->current = r_framedata_mem->mark;
3705 }
3706
3707 //==================================================================================
3708
3709 // avoid reusing the same buffer objects on consecutive frames
3710 #define R_BUFFERDATA_CYCLE 3
3711
3712 typedef struct r_bufferdata_buffer_s
3713 {
3714         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3715         size_t size; // how much usable space
3716         size_t current; // how much space in use
3717         r_meshbuffer_t *buffer; // the buffer itself
3718 }
3719 r_bufferdata_buffer_t;
3720
3721 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3722 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3723
3724 /// frees all dynamic buffers
3725 void R_BufferData_Reset(void)
3726 {
3727         int cycle, type;
3728         r_bufferdata_buffer_t **p, *mem;
3729         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3730         {
3731                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3732                 {
3733                         // free all buffers
3734                         p = &r_bufferdata_buffer[cycle][type];
3735                         while (*p)
3736                         {
3737                                 mem = *p;
3738                                 *p = (*p)->purge;
3739                                 if (mem->buffer)
3740                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3741                                 Mem_Free(mem);
3742                         }
3743                 }
3744         }
3745 }
3746
3747 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3748 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3749 {
3750         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3751         size_t size;
3752         float newvalue = r_buffermegs[type].value;
3753
3754         // increase the cvar if we have to (but only if we already have a mem)
3755         if (mustgrow && mem)
3756                 newvalue *= 2.0f;
3757         newvalue = bound(0.25f, newvalue, 256.0f);
3758         while (newvalue * 1024*1024 < minsize)
3759                 newvalue *= 2.0f;
3760
3761         // clamp the cvar to valid range
3762         newvalue = bound(0.25f, newvalue, 256.0f);
3763         if (r_buffermegs[type].value != newvalue)
3764                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3765
3766         // calculate size in bytes
3767         size = (size_t)(newvalue * 1024*1024);
3768         size = bound(131072, size, 256*1024*1024);
3769
3770         // allocate a new buffer if the size is different (purge old one later)
3771         // or if we were told we must grow the buffer
3772         if (!mem || mem->size != size || mustgrow)
3773         {
3774                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3775                 mem->size = size;
3776                 mem->current = 0;
3777                 if (type == R_BUFFERDATA_VERTEX)
3778                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3779                 else if (type == R_BUFFERDATA_INDEX16)
3780                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3781                 else if (type == R_BUFFERDATA_INDEX32)
3782                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3783                 else if (type == R_BUFFERDATA_UNIFORM)
3784                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3785                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3786                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3787         }
3788 }
3789
3790 void R_BufferData_NewFrame(void)
3791 {
3792         int type;
3793         r_bufferdata_buffer_t **p, *mem;
3794         // cycle to the next frame's buffers
3795         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3796         // if we ran out of space on the last time we used these buffers, free the old memory now
3797         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3798         {
3799                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3800                 {
3801                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3802                         // free all but the head buffer, this is how we recycle obsolete
3803                         // buffers after they are no longer in use
3804                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3805                         while (*p)
3806                         {
3807                                 mem = *p;
3808                                 *p = (*p)->purge;
3809                                 if (mem->buffer)
3810                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3811                                 Mem_Free(mem);
3812                         }
3813                         // reset the current offset
3814                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3815                 }
3816         }
3817 }
3818
3819 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3820 {
3821         r_bufferdata_buffer_t *mem;
3822         int offset = 0;
3823         int padsize;
3824
3825         *returnbufferoffset = 0;
3826
3827         // align size to a byte boundary appropriate for the buffer type, this
3828         // makes all allocations have aligned start offsets
3829         if (type == R_BUFFERDATA_UNIFORM)
3830                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3831         else
3832                 padsize = (datasize + 15) & ~15;
3833
3834         // if we ran out of space in this buffer we must allocate a new one
3835         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3836                 R_BufferData_Resize(type, true, padsize);
3837
3838         // if the resize did not give us enough memory, fail
3839         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3840                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3841
3842         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3843         offset = (int)mem->current;
3844         mem->current += padsize;
3845
3846         // upload the data to the buffer at the chosen offset
3847         if (offset == 0)
3848                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3849         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3850
3851         // count the usage for stats
3852         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3853         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3854
3855         // return the buffer offset
3856         *returnbufferoffset = offset;
3857
3858         return mem->buffer;
3859 }
3860
3861 //==================================================================================
3862
3863 // LadyHavoc: animcache originally written by Echon, rewritten since then
3864
3865 /**
3866  * Animation cache prevents re-generating mesh data for an animated model
3867  * multiple times in one frame for lighting, shadowing, reflections, etc.
3868  */
3869
3870 void R_AnimCache_Free(void)
3871 {
3872 }
3873
3874 void R_AnimCache_ClearCache(void)
3875 {
3876         int i;
3877         entity_render_t *ent;
3878
3879         for (i = 0;i < r_refdef.scene.numentities;i++)
3880         {
3881                 ent = r_refdef.scene.entities[i];
3882                 ent->animcache_vertex3f = NULL;
3883                 ent->animcache_vertex3f_vertexbuffer = NULL;
3884                 ent->animcache_vertex3f_bufferoffset = 0;
3885                 ent->animcache_normal3f = NULL;
3886                 ent->animcache_normal3f_vertexbuffer = NULL;
3887                 ent->animcache_normal3f_bufferoffset = 0;
3888                 ent->animcache_svector3f = NULL;
3889                 ent->animcache_svector3f_vertexbuffer = NULL;
3890                 ent->animcache_svector3f_bufferoffset = 0;
3891                 ent->animcache_tvector3f = NULL;
3892                 ent->animcache_tvector3f_vertexbuffer = NULL;
3893                 ent->animcache_tvector3f_bufferoffset = 0;
3894                 ent->animcache_skeletaltransform3x4 = NULL;
3895                 ent->animcache_skeletaltransform3x4buffer = NULL;
3896                 ent->animcache_skeletaltransform3x4offset = 0;
3897                 ent->animcache_skeletaltransform3x4size = 0;
3898         }
3899 }
3900
3901 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3902 {
3903         dp_model_t *model = ent->model;
3904         int numvertices;
3905
3906         // see if this ent is worth caching
3907         if (!model || !model->Draw || !model->AnimateVertices)
3908                 return false;
3909         // nothing to cache if it contains no animations and has no skeleton
3910         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3911                 return false;
3912         // see if it is already cached for gpuskeletal
3913         if (ent->animcache_skeletaltransform3x4)
3914                 return false;
3915         // see if it is already cached as a mesh
3916         if (ent->animcache_vertex3f)
3917         {
3918                 // check if we need to add normals or tangents
3919                 if (ent->animcache_normal3f)
3920                         wantnormals = false;
3921                 if (ent->animcache_svector3f)
3922                         wanttangents = false;
3923                 if (!wantnormals && !wanttangents)
3924                         return false;
3925         }
3926
3927         // check which kind of cache we need to generate
3928         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3929         {
3930                 // cache the skeleton so the vertex shader can use it
3931                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3932                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3933                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3934                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3935                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3936                 // note: this can fail if the buffer is at the grow limit
3937                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3938                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3939         }
3940         else if (ent->animcache_vertex3f)
3941         {
3942                 // mesh was already cached but we may need to add normals/tangents
3943                 // (this only happens with multiple views, reflections, cameras, etc)
3944                 if (wantnormals || wanttangents)
3945                 {
3946                         numvertices = model->surfmesh.num_vertices;
3947                         if (wantnormals)
3948                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3949                         if (wanttangents)
3950                         {
3951                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3952                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3953                         }
3954                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3955                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3956                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3957                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3958                 }
3959         }
3960         else
3961         {
3962                 // generate mesh cache
3963                 numvertices = model->surfmesh.num_vertices;
3964                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3965                 if (wantnormals)
3966                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3967                 if (wanttangents)
3968                 {
3969                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3970                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3971                 }
3972                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3973                 if (wantnormals || wanttangents)
3974                 {
3975                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3976                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3977                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3978                 }
3979                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3980                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3981                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3982         }
3983         return true;
3984 }
3985
3986 void R_AnimCache_CacheVisibleEntities(void)
3987 {
3988         int i;
3989
3990         // TODO: thread this
3991         // NOTE: R_PrepareRTLights() also caches entities
3992
3993         for (i = 0;i < r_refdef.scene.numentities;i++)
3994                 if (r_refdef.viewcache.entityvisible[i])
3995                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3996 }
3997
3998 //==================================================================================
3999
4000 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
4001 {
4002         long unsigned int i;
4003         int j;
4004         vec3_t eyemins, eyemaxs;
4005         vec3_t boxmins, boxmaxs;
4006         vec3_t padmins, padmaxs;
4007         vec3_t start;
4008         vec3_t end;
4009         dp_model_t *model = r_refdef.scene.worldmodel;
4010         static vec3_t positions[] = {
4011                 { 0.5f, 0.5f, 0.5f },
4012                 { 0.0f, 0.0f, 0.0f },
4013                 { 0.0f, 0.0f, 1.0f },
4014                 { 0.0f, 1.0f, 0.0f },
4015                 { 0.0f, 1.0f, 1.0f },
4016                 { 1.0f, 0.0f, 0.0f },
4017                 { 1.0f, 0.0f, 1.0f },
4018                 { 1.0f, 1.0f, 0.0f },
4019                 { 1.0f, 1.0f, 1.0f },
4020         };
4021
4022         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4023         if (numsamples < 0)
4024                 return true;
4025
4026         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4027         if (!r_refdef.view.usevieworiginculling)
4028                 return true;
4029
4030         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4031                 return true;
4032
4033         // expand the eye box a little
4034         eyemins[0] = eye[0] - eyejitter;
4035         eyemaxs[0] = eye[0] + eyejitter;
4036         eyemins[1] = eye[1] - eyejitter;
4037         eyemaxs[1] = eye[1] + eyejitter;
4038         eyemins[2] = eye[2] - eyejitter;
4039         eyemaxs[2] = eye[2] + eyejitter;
4040         // expand the box a little
4041         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4042         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4043         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4044         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4045         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4046         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4047         // make an even larger box for the acceptable area
4048         padmins[0] = boxmins[0] - pad;
4049         padmaxs[0] = boxmaxs[0] + pad;
4050         padmins[1] = boxmins[1] - pad;
4051         padmaxs[1] = boxmaxs[1] + pad;
4052         padmins[2] = boxmins[2] - pad;
4053         padmaxs[2] = boxmaxs[2] + pad;
4054
4055         // return true if eye overlaps enlarged box
4056         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4057                 return true;
4058
4059         // try specific positions in the box first - note that these can be cached
4060         if (r_cullentities_trace_entityocclusion.integer)
4061         {
4062                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4063                 {
4064                         trace_t trace;
4065                         VectorCopy(eye, start);
4066                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4067                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4068                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4069                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4070                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4071                         // not picky - if the trace ended anywhere in the box we're good
4072                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4073                                 return true;
4074                 }
4075         }
4076         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4077                 return true;
4078
4079         // try various random positions
4080         for (j = 0; j < numsamples; j++)
4081         {
4082                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4083                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4084                 if (r_cullentities_trace_entityocclusion.integer)
4085                 {
4086                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4087                         // not picky - if the trace ended anywhere in the box we're good
4088                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4089                                 return true;
4090                 }
4091                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4092                         return true;
4093         }
4094
4095         return false;
4096 }
4097
4098
4099 static void R_View_UpdateEntityVisible (void)
4100 {
4101         int i;
4102         int renderimask;
4103         int samples;
4104         entity_render_t *ent;
4105
4106         if (r_refdef.envmap || r_fb.water.hideplayer)
4107                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4108         else if (chase_active.integer || r_fb.water.renderingscene)
4109                 renderimask = RENDER_VIEWMODEL;
4110         else
4111                 renderimask = RENDER_EXTERIORMODEL;
4112         if (!r_drawviewmodel.integer)
4113                 renderimask |= RENDER_VIEWMODEL;
4114         if (!r_drawexteriormodel.integer)
4115                 renderimask |= RENDER_EXTERIORMODEL;
4116         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4117         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4118         {
4119                 // worldmodel can check visibility
4120                 for (i = 0;i < r_refdef.scene.numentities;i++)
4121                 {
4122                         ent = r_refdef.scene.entities[i];
4123                         if (!(ent->flags & renderimask))
4124                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4125                         if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4126                                 r_refdef.viewcache.entityvisible[i] = true;
4127                 }
4128         }
4129         else
4130         {
4131                 // no worldmodel or it can't check visibility
4132                 for (i = 0;i < r_refdef.scene.numentities;i++)
4133                 {
4134                         ent = r_refdef.scene.entities[i];
4135                         if (!(ent->flags & renderimask))
4136                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4137                                 r_refdef.viewcache.entityvisible[i] = true;
4138                 }
4139         }
4140         if (r_cullentities_trace.integer)
4141         {
4142                 for (i = 0;i < r_refdef.scene.numentities;i++)
4143                 {
4144                         if (!r_refdef.viewcache.entityvisible[i])
4145                                 continue;
4146                         ent = r_refdef.scene.entities[i];
4147                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4148                         {
4149                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4150                                 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4151                                         ent->last_trace_visibility = host.realtime;
4152                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4153                                         r_refdef.viewcache.entityvisible[i] = 0;
4154                         }
4155                 }
4156         }
4157 }
4158
4159 /// only used if skyrendermasked, and normally returns false
4160 static int R_DrawBrushModelsSky (void)
4161 {
4162         int i, sky;
4163         entity_render_t *ent;
4164
4165         sky = false;
4166         for (i = 0;i < r_refdef.scene.numentities;i++)
4167         {
4168                 if (!r_refdef.viewcache.entityvisible[i])
4169                         continue;
4170                 ent = r_refdef.scene.entities[i];
4171                 if (!ent->model || !ent->model->DrawSky)
4172                         continue;
4173                 ent->model->DrawSky(ent);
4174                 sky = true;
4175         }
4176         return sky;
4177 }
4178
4179 static void R_DrawNoModel(entity_render_t *ent);
4180 static void R_DrawModels(void)
4181 {
4182         int i;
4183         entity_render_t *ent;
4184
4185         for (i = 0;i < r_refdef.scene.numentities;i++)
4186         {
4187                 if (!r_refdef.viewcache.entityvisible[i])
4188                         continue;
4189                 ent = r_refdef.scene.entities[i];
4190                 r_refdef.stats[r_stat_entities]++;
4191                 /*
4192                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4193                 {
4194                         vec3_t f, l, u, o;
4195                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4196                         Con_Printf("R_DrawModels\n");
4197                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4198                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4199                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4200                 }
4201                 */
4202                 if (ent->model && ent->model->Draw != NULL)
4203                         ent->model->Draw(ent);
4204                 else
4205                         R_DrawNoModel(ent);
4206         }
4207 }
4208
4209 static void R_DrawModelsDepth(void)
4210 {
4211         int i;
4212         entity_render_t *ent;
4213
4214         for (i = 0;i < r_refdef.scene.numentities;i++)
4215         {
4216                 if (!r_refdef.viewcache.entityvisible[i])
4217                         continue;
4218                 ent = r_refdef.scene.entities[i];
4219                 if (ent->model && ent->model->DrawDepth != NULL)
4220                         ent->model->DrawDepth(ent);
4221         }
4222 }
4223
4224 static void R_DrawModelsDebug(void)
4225 {
4226         int i;
4227         entity_render_t *ent;
4228
4229         for (i = 0;i < r_refdef.scene.numentities;i++)
4230         {
4231                 if (!r_refdef.viewcache.entityvisible[i])
4232                         continue;
4233                 ent = r_refdef.scene.entities[i];
4234                 if (ent->model && ent->model->DrawDebug != NULL)
4235                         ent->model->DrawDebug(ent);
4236         }
4237 }
4238
4239 static void R_DrawModelsAddWaterPlanes(void)
4240 {
4241         int i;
4242         entity_render_t *ent;
4243
4244         for (i = 0;i < r_refdef.scene.numentities;i++)
4245         {
4246                 if (!r_refdef.viewcache.entityvisible[i])
4247                         continue;
4248                 ent = r_refdef.scene.entities[i];
4249                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4250                         ent->model->DrawAddWaterPlanes(ent);
4251         }
4252 }
4253
4254 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4255
4256 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4257 {
4258         if (r_hdr_irisadaptation.integer)
4259         {
4260                 vec3_t p;
4261                 vec3_t ambient;
4262                 vec3_t diffuse;
4263                 vec3_t diffusenormal;
4264                 vec3_t forward;
4265                 vec_t brightness = 0.0f;
4266                 vec_t goal;
4267                 vec_t current;
4268                 vec_t d;
4269                 int c;
4270                 VectorCopy(r_refdef.view.forward, forward);
4271                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4272                 {
4273                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4274                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4275                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4276                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4277                         d = DotProduct(forward, diffusenormal);
4278                         brightness += VectorLength(ambient);
4279                         if (d > 0)
4280                                 brightness += d * VectorLength(diffuse);
4281                 }
4282                 brightness *= 1.0f / c;
4283                 brightness += 0.00001f; // make sure it's never zero
4284                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4285                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4286                 current = r_hdr_irisadaptation_value.value;
4287                 if (current < goal)
4288                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4289                 else if (current > goal)
4290                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4291                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4292                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4293         }
4294         else if (r_hdr_irisadaptation_value.value != 1.0f)
4295                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4296 }
4297
4298 extern cvar_t r_lockvisibility;
4299 extern cvar_t r_lockpvs;
4300
4301 static void R_View_SetFrustum(const int *scissor)
4302 {
4303         int i;
4304         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4305         vec3_t forward, left, up, origin, v;
4306         if(r_lockvisibility.integer || r_lockpvs.integer)
4307                 return;
4308         if(scissor)
4309         {
4310                 // flipped x coordinates (because x points left here)
4311                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4312                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4313                 // non-flipped y coordinates
4314                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4315                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4316         }
4317
4318         // we can't trust r_refdef.view.forward and friends in reflected scenes
4319         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4320
4321 #if 0
4322         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4323         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4324         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4325         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4326         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4327         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4328         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4329         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4330         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4331         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4332         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4333         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4334 #endif
4335
4336 #if 0
4337         zNear = r_refdef.nearclip;
4338         nudge = 1.0 - 1.0 / (1<<23);
4339         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4340         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4341         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4342         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4343         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4344         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4345         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4346         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4347 #endif
4348
4349
4350
4351 #if 0
4352         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4353         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4354         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4355         r_refdef.view.frustum[0].dist = m[15] - m[12];
4356
4357         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4358         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4359         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4360         r_refdef.view.frustum[1].dist = m[15] + m[12];
4361
4362         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4363         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4364         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4365         r_refdef.view.frustum[2].dist = m[15] - m[13];
4366
4367         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4368         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4369         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4370         r_refdef.view.frustum[3].dist = m[15] + m[13];
4371
4372         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4373         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4374         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4375         r_refdef.view.frustum[4].dist = m[15] - m[14];
4376
4377         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4378         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4379         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4380         r_refdef.view.frustum[5].dist = m[15] + m[14];
4381 #endif
4382
4383         if (r_refdef.view.useperspective)
4384         {
4385                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4386                 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]);
4387                 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]);
4388                 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]);
4389                 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]);
4390
4391                 // then the normals from the corners relative to origin
4392                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4393                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4394                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4395                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4396
4397                 // in a NORMAL view, forward cross left == up
4398                 // in a REFLECTED view, forward cross left == down
4399                 // so our cross products above need to be adjusted for a left handed coordinate system
4400                 CrossProduct(forward, left, v);
4401                 if(DotProduct(v, up) < 0)
4402                 {
4403                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4404                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4405                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4406                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4407                 }
4408
4409                 // Leaving those out was a mistake, those were in the old code, and they
4410                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4411                 // I couldn't reproduce it after adding those normalizations. --blub
4412                 VectorNormalize(r_refdef.view.frustum[0].normal);
4413                 VectorNormalize(r_refdef.view.frustum[1].normal);
4414                 VectorNormalize(r_refdef.view.frustum[2].normal);
4415                 VectorNormalize(r_refdef.view.frustum[3].normal);
4416
4417                 // make the corners absolute
4418                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4419                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4420                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4421                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4422
4423                 // one more normal
4424                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4425
4426                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4427                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4428                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4429                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4430                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4431         }
4432         else
4433         {
4434                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4435                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4436                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4437                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4438                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4439                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4440                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4441                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4442                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4443                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4444         }
4445         r_refdef.view.numfrustumplanes = 5;
4446
4447         if (r_refdef.view.useclipplane)
4448         {
4449                 r_refdef.view.numfrustumplanes = 6;
4450                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4451         }
4452
4453         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4454                 PlaneClassify(r_refdef.view.frustum + i);
4455
4456         // LadyHavoc: note to all quake engine coders, Quake had a special case
4457         // for 90 degrees which assumed a square view (wrong), so I removed it,
4458         // Quake2 has it disabled as well.
4459
4460         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4461         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4462         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4463         //PlaneClassify(&frustum[0]);
4464
4465         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4466         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4467         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4468         //PlaneClassify(&frustum[1]);
4469
4470         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4471         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4472         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4473         //PlaneClassify(&frustum[2]);
4474
4475         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4476         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4477         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4478         //PlaneClassify(&frustum[3]);
4479
4480         // nearclip plane
4481         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4482         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4483         //PlaneClassify(&frustum[4]);
4484 }
4485
4486 static void R_View_UpdateWithScissor(const int *myscissor)
4487 {
4488         R_Main_ResizeViewCache();
4489         R_View_SetFrustum(myscissor);
4490         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4491         R_View_UpdateEntityVisible();
4492 }
4493
4494 static void R_View_Update(void)
4495 {
4496         R_Main_ResizeViewCache();
4497         R_View_SetFrustum(NULL);
4498         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4499         R_View_UpdateEntityVisible();
4500 }
4501
4502 float viewscalefpsadjusted = 1.0f;
4503
4504 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4505 {
4506         const float *customclipplane = NULL;
4507         float plane[4];
4508         int /*rtwidth,*/ rtheight;
4509         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4510         {
4511                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4512                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4513                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4514                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4515                         dist = r_refdef.view.clipplane.dist;
4516                 plane[0] = r_refdef.view.clipplane.normal[0];
4517                 plane[1] = r_refdef.view.clipplane.normal[1];
4518                 plane[2] = r_refdef.view.clipplane.normal[2];
4519                 plane[3] = -dist;
4520                 customclipplane = plane;
4521         }
4522
4523         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4524         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4525
4526         if (!r_refdef.view.useperspective)
4527                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4528         else if (vid.stencil && r_useinfinitefarclip.integer)
4529                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4530         else
4531                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4532         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4533         R_SetViewport(&r_refdef.view.viewport);
4534 }
4535
4536 void R_EntityMatrix(const matrix4x4_t *matrix)
4537 {
4538         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4539         {
4540                 gl_modelmatrixchanged = false;
4541                 gl_modelmatrix = *matrix;
4542                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4543                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4544                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4545                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4546                 CHECKGLERROR
4547                 switch(vid.renderpath)
4548                 {
4549                 case RENDERPATH_GL32:
4550                 case RENDERPATH_GLES2:
4551                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4552                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4553                         break;
4554                 }
4555         }
4556 }
4557
4558 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4559 {
4560         r_viewport_t viewport;
4561
4562         CHECKGLERROR
4563
4564         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4565         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4566         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4567         R_SetViewport(&viewport);
4568         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4569         GL_Color(1, 1, 1, 1);
4570         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4571         GL_BlendFunc(GL_ONE, GL_ZERO);
4572         GL_ScissorTest(false);
4573         GL_DepthMask(false);
4574         GL_DepthRange(0, 1);
4575         GL_DepthTest(false);
4576         GL_DepthFunc(GL_LEQUAL);
4577         R_EntityMatrix(&identitymatrix);
4578         R_Mesh_ResetTextureState();
4579         GL_PolygonOffset(0, 0);
4580         switch(vid.renderpath)
4581         {
4582         case RENDERPATH_GL32:
4583         case RENDERPATH_GLES2:
4584                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4585                 break;
4586         }
4587         GL_CullFace(GL_NONE);
4588
4589         CHECKGLERROR
4590 }
4591
4592 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4593 {
4594         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4595 }
4596
4597 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4598 {
4599         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4600         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4601         GL_Color(1, 1, 1, 1);
4602         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4603         GL_BlendFunc(GL_ONE, GL_ZERO);
4604         GL_ScissorTest(true);
4605         GL_DepthMask(true);
4606         GL_DepthRange(0, 1);
4607         GL_DepthTest(true);
4608         GL_DepthFunc(GL_LEQUAL);
4609         R_EntityMatrix(&identitymatrix);
4610         R_Mesh_ResetTextureState();
4611         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4612         switch(vid.renderpath)
4613         {
4614         case RENDERPATH_GL32:
4615         case RENDERPATH_GLES2:
4616                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4617                 break;
4618         }
4619         GL_CullFace(r_refdef.view.cullface_back);
4620 }
4621
4622 /*
4623 ================
4624 R_RenderView_UpdateViewVectors
4625 ================
4626 */
4627 void R_RenderView_UpdateViewVectors(void)
4628 {
4629         // break apart the view matrix into vectors for various purposes
4630         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4631         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4632         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4633         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4634         // make an inverted copy of the view matrix for tracking sprites
4635         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4636 }
4637
4638 void R_RenderTarget_FreeUnused(qboolean force)
4639 {
4640         unsigned int i, j, end;
4641         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4642         for (i = 0; i < end; i++)
4643         {
4644                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4645                 // free resources for rendertargets that have not been used for a while
4646                 // (note: this check is run after the frame render, so any targets used
4647                 // this frame will not be affected even at low framerates)
4648                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4649                 {
4650                         if (r->fbo)
4651                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4652                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4653                                 if (r->colortexture[j])
4654                                         R_FreeTexture(r->colortexture[j]);
4655                         if (r->depthtexture)
4656                                 R_FreeTexture(r->depthtexture);
4657                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4658                 }
4659         }
4660 }
4661
4662 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4663 {
4664         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4665         x1 = x * iw;
4666         x2 = (x + w) * iw;
4667         y1 = (th - y) * ih;
4668         y2 = (th - y - h) * ih;
4669         texcoord2f[0] = x1;
4670         texcoord2f[2] = x2;
4671         texcoord2f[4] = x2;
4672         texcoord2f[6] = x1;
4673         texcoord2f[1] = y1;
4674         texcoord2f[3] = y1;
4675         texcoord2f[5] = y2;
4676         texcoord2f[7] = y2;
4677 }
4678
4679 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4680 {
4681         unsigned int i, j, end;
4682         r_rendertarget_t *r = NULL;
4683         char vabuf[256];
4684         // first try to reuse an existing slot if possible
4685         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4686         for (i = 0; i < end; i++)
4687         {
4688                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4689                 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)
4690                         break;
4691         }
4692         if (i == end)
4693         {
4694                 // no unused exact match found, so we have to make one in the first unused slot
4695                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4696                 r->texturewidth = texturewidth;
4697                 r->textureheight = textureheight;
4698                 r->colortextype[0] = colortextype0;
4699                 r->colortextype[1] = colortextype1;
4700                 r->colortextype[2] = colortextype2;
4701                 r->colortextype[3] = colortextype3;
4702                 r->depthtextype = depthtextype;
4703                 r->depthisrenderbuffer = depthisrenderbuffer;
4704                 for (j = 0; j < 4; j++)
4705                         if (r->colortextype[j])
4706                                 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);
4707                 if (r->depthtextype)
4708                 {
4709                         if (r->depthisrenderbuffer)
4710                                 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);
4711                         else
4712                                 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);
4713                 }
4714                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4715         }
4716         r_refdef.stats[r_stat_rendertargets_used]++;
4717         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4718         r->lastusetime = host.realtime;
4719         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4720         return r;
4721 }
4722
4723 static void R_Water_StartFrame(int viewwidth, int viewheight)
4724 {
4725         int waterwidth, waterheight;
4726
4727         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4728                 return;
4729
4730         // set waterwidth and waterheight to the water resolution that will be
4731         // used (often less than the screen resolution for faster rendering)
4732         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4733         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4734
4735         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4736                 waterwidth = waterheight = 0;
4737
4738         // set up variables that will be used in shader setup
4739         r_fb.water.waterwidth = waterwidth;
4740         r_fb.water.waterheight = waterheight;
4741         r_fb.water.texturewidth = waterwidth;
4742         r_fb.water.textureheight = waterheight;
4743         r_fb.water.camerawidth = waterwidth;
4744         r_fb.water.cameraheight = waterheight;
4745         r_fb.water.screenscale[0] = 0.5f;
4746         r_fb.water.screenscale[1] = 0.5f;
4747         r_fb.water.screencenter[0] = 0.5f;
4748         r_fb.water.screencenter[1] = 0.5f;
4749         r_fb.water.enabled = waterwidth != 0;
4750
4751         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4752         r_fb.water.numwaterplanes = 0;
4753 }
4754
4755 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4756 {
4757         int planeindex, bestplaneindex, vertexindex;
4758         vec3_t mins, maxs, normal, center, v, n;
4759         vec_t planescore, bestplanescore;
4760         mplane_t plane;
4761         r_waterstate_waterplane_t *p;
4762         texture_t *t = R_GetCurrentTexture(surface->texture);
4763
4764         rsurface.texture = t;
4765         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4766         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4767         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4768                 return;
4769         // average the vertex normals, find the surface bounds (after deformvertexes)
4770         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4771         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4772         VectorCopy(n, normal);
4773         VectorCopy(v, mins);
4774         VectorCopy(v, maxs);
4775         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4776         {
4777                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4778                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4779                 VectorAdd(normal, n, normal);
4780                 mins[0] = min(mins[0], v[0]);
4781                 mins[1] = min(mins[1], v[1]);
4782                 mins[2] = min(mins[2], v[2]);
4783                 maxs[0] = max(maxs[0], v[0]);
4784                 maxs[1] = max(maxs[1], v[1]);
4785                 maxs[2] = max(maxs[2], v[2]);
4786         }
4787         VectorNormalize(normal);
4788         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4789
4790         VectorCopy(normal, plane.normal);
4791         VectorNormalize(plane.normal);
4792         plane.dist = DotProduct(center, plane.normal);
4793         PlaneClassify(&plane);
4794         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4795         {
4796                 // skip backfaces (except if nocullface is set)
4797 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4798 //                      return;
4799                 VectorNegate(plane.normal, plane.normal);
4800                 plane.dist *= -1;
4801                 PlaneClassify(&plane);
4802         }
4803
4804
4805         // find a matching plane if there is one
4806         bestplaneindex = -1;
4807         bestplanescore = 1048576.0f;
4808         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4809         {
4810                 if(p->camera_entity == t->camera_entity)
4811                 {
4812                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4813                         if (bestplaneindex < 0 || bestplanescore > planescore)
4814                         {
4815                                 bestplaneindex = planeindex;
4816                                 bestplanescore = planescore;
4817                         }
4818                 }
4819         }
4820         planeindex = bestplaneindex;
4821
4822         // if this surface does not fit any known plane rendered this frame, add one
4823         if (planeindex < 0 || bestplanescore > 0.001f)
4824         {
4825                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4826                 {
4827                         // store the new plane
4828                         planeindex = r_fb.water.numwaterplanes++;
4829                         p = r_fb.water.waterplanes + planeindex;
4830                         p->plane = plane;
4831                         // clear materialflags and pvs
4832                         p->materialflags = 0;
4833                         p->pvsvalid = false;
4834                         p->camera_entity = t->camera_entity;
4835                         VectorCopy(mins, p->mins);
4836                         VectorCopy(maxs, p->maxs);
4837                 }
4838                 else
4839                 {
4840                         // We're totally screwed.
4841                         return;
4842                 }
4843         }
4844         else
4845         {
4846                 // merge mins/maxs when we're adding this surface to the plane
4847                 p = r_fb.water.waterplanes + planeindex;
4848                 p->mins[0] = min(p->mins[0], mins[0]);
4849                 p->mins[1] = min(p->mins[1], mins[1]);
4850                 p->mins[2] = min(p->mins[2], mins[2]);
4851                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4852                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4853                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4854         }
4855         // merge this surface's materialflags into the waterplane
4856         p->materialflags |= t->currentmaterialflags;
4857         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4858         {
4859                 // merge this surface's PVS into the waterplane
4860                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4861                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4862                 {
4863                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4864                         p->pvsvalid = true;
4865                 }
4866         }
4867 }
4868
4869 extern cvar_t r_drawparticles;
4870 extern cvar_t r_drawdecals;
4871
4872 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4873 {
4874         int myscissor[4];
4875         r_refdef_view_t originalview;
4876         r_refdef_view_t myview;
4877         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;
4878         r_waterstate_waterplane_t *p;
4879         vec3_t visorigin;
4880         r_rendertarget_t *rt;
4881
4882         originalview = r_refdef.view;
4883
4884         // lowquality hack, temporarily shut down some cvars and restore afterwards
4885         qualityreduction = r_water_lowquality.integer;
4886         if (qualityreduction > 0)
4887         {
4888                 if (qualityreduction >= 1)
4889                 {
4890                         old_r_shadows = r_shadows.integer;
4891                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4892                         old_r_dlight = r_shadow_realtime_dlight.integer;
4893                         Cvar_SetValueQuick(&r_shadows, 0);
4894                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4895                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4896                 }
4897                 if (qualityreduction >= 2)
4898                 {
4899                         old_r_dynamic = r_dynamic.integer;
4900                         old_r_particles = r_drawparticles.integer;
4901                         old_r_decals = r_drawdecals.integer;
4902                         Cvar_SetValueQuick(&r_dynamic, 0);
4903                         Cvar_SetValueQuick(&r_drawparticles, 0);
4904                         Cvar_SetValueQuick(&r_drawdecals, 0);
4905                 }
4906         }
4907
4908         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4909         {
4910                 p->rt_reflection = NULL;
4911                 p->rt_refraction = NULL;
4912                 p->rt_camera = NULL;
4913         }
4914
4915         // render views
4916         r_refdef.view = originalview;
4917         r_refdef.view.showdebug = false;
4918         r_refdef.view.width = r_fb.water.waterwidth;
4919         r_refdef.view.height = r_fb.water.waterheight;
4920         r_refdef.view.useclipplane = true;
4921         myview = r_refdef.view;
4922         r_fb.water.renderingscene = true;
4923         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4924         {
4925                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4926                         continue;
4927
4928                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4929                 {
4930                         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);
4931                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4932                                 goto error;
4933                         r_refdef.view = myview;
4934                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4935                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4936                         if(r_water_scissormode.integer)
4937                         {
4938                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4939                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4940                                 {
4941                                         p->rt_reflection = NULL;
4942                                         p->rt_refraction = NULL;
4943                                         p->rt_camera = NULL;
4944                                         continue;
4945                                 }
4946                         }
4947
4948                         r_refdef.view.clipplane = p->plane;
4949                         // reflected view origin may be in solid, so don't cull with it
4950                         r_refdef.view.usevieworiginculling = false;
4951                         // reverse the cullface settings for this render
4952                         r_refdef.view.cullface_front = GL_FRONT;
4953                         r_refdef.view.cullface_back = GL_BACK;
4954                         // combined pvs (based on what can be seen from each surface center)
4955                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4956                         {
4957                                 r_refdef.view.usecustompvs = true;
4958                                 if (p->pvsvalid)
4959                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4960                                 else
4961                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4962                         }
4963
4964                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4965                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4966                         GL_ScissorTest(false);
4967                         R_ClearScreen(r_refdef.fogenabled);
4968                         GL_ScissorTest(true);
4969                         if(r_water_scissormode.integer & 2)
4970                                 R_View_UpdateWithScissor(myscissor);
4971                         else
4972                                 R_View_Update();
4973                         R_AnimCache_CacheVisibleEntities();
4974                         if(r_water_scissormode.integer & 1)
4975                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4976                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4977
4978                         r_fb.water.hideplayer = false;
4979                         p->rt_reflection = rt;
4980                 }
4981
4982                 // render the normal view scene and copy into texture
4983                 // (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)
4984                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4985                 {
4986                         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);
4987                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4988                                 goto error;
4989                         r_refdef.view = myview;
4990                         if(r_water_scissormode.integer)
4991                         {
4992                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4993                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4994                                 {
4995                                         p->rt_reflection = NULL;
4996                                         p->rt_refraction = NULL;
4997                                         p->rt_camera = NULL;
4998                                         continue;
4999                                 }
5000                         }
5001
5002                         // combined pvs (based on what can be seen from each surface center)
5003                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
5004                         {
5005                                 r_refdef.view.usecustompvs = true;
5006                                 if (p->pvsvalid)
5007                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5008                                 else
5009                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5010                         }
5011
5012                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5013
5014                         r_refdef.view.clipplane = p->plane;
5015                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5016                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5017
5018                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5019                         {
5020                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5021                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5022                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5023                                 R_RenderView_UpdateViewVectors();
5024                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5025                                 {
5026                                         r_refdef.view.usecustompvs = true;
5027                                         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);
5028                                 }
5029                         }
5030
5031                         PlaneClassify(&r_refdef.view.clipplane);
5032
5033                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5034                         GL_ScissorTest(false);
5035                         R_ClearScreen(r_refdef.fogenabled);
5036                         GL_ScissorTest(true);
5037                         if(r_water_scissormode.integer & 2)
5038                                 R_View_UpdateWithScissor(myscissor);
5039                         else
5040                                 R_View_Update();
5041                         R_AnimCache_CacheVisibleEntities();
5042                         if(r_water_scissormode.integer & 1)
5043                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5044                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5045
5046                         r_fb.water.hideplayer = false;
5047                         p->rt_refraction = rt;
5048                 }
5049                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5050                 {
5051                         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);
5052                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5053                                 goto error;
5054                         r_refdef.view = myview;
5055
5056                         r_refdef.view.clipplane = p->plane;
5057                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5058                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5059
5060                         r_refdef.view.width = r_fb.water.camerawidth;
5061                         r_refdef.view.height = r_fb.water.cameraheight;
5062                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5063                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5064                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5065                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5066
5067                         if(p->camera_entity)
5068                         {
5069                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5070                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5071                         }
5072
5073                         // note: all of the view is used for displaying... so
5074                         // there is no use in scissoring
5075
5076                         // reverse the cullface settings for this render
5077                         r_refdef.view.cullface_front = GL_FRONT;
5078                         r_refdef.view.cullface_back = GL_BACK;
5079                         // also reverse the view matrix
5080                         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
5081                         R_RenderView_UpdateViewVectors();
5082                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5083                         {
5084                                 r_refdef.view.usecustompvs = true;
5085                                 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);
5086                         }
5087                         
5088                         // camera needs no clipplane
5089                         r_refdef.view.useclipplane = false;
5090                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5091                         r_refdef.view.usevieworiginculling = false;
5092
5093                         PlaneClassify(&r_refdef.view.clipplane);
5094
5095                         r_fb.water.hideplayer = false;
5096
5097                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5098                         GL_ScissorTest(false);
5099                         R_ClearScreen(r_refdef.fogenabled);
5100                         GL_ScissorTest(true);
5101                         R_View_Update();
5102                         R_AnimCache_CacheVisibleEntities();
5103                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5104
5105                         r_fb.water.hideplayer = false;
5106                         p->rt_camera = rt;
5107                 }
5108
5109         }
5110         r_fb.water.renderingscene = false;
5111         r_refdef.view = originalview;
5112         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5113         R_View_Update();
5114         R_AnimCache_CacheVisibleEntities();
5115         goto finish;
5116 error:
5117         r_refdef.view = originalview;
5118         r_fb.water.renderingscene = false;
5119         Cvar_SetValueQuick(&r_water, 0);
5120         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5121 finish:
5122         // lowquality hack, restore cvars
5123         if (qualityreduction > 0)
5124         {
5125                 if (qualityreduction >= 1)
5126                 {
5127                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5128                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5129                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5130                 }
5131                 if (qualityreduction >= 2)
5132                 {
5133                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5134                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5135                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5136                 }
5137         }
5138 }
5139
5140 static void R_Bloom_StartFrame(void)
5141 {
5142         int screentexturewidth, screentextureheight;
5143         textype_t textype = TEXTYPE_COLORBUFFER;
5144         double scale;
5145
5146         // clear the pointers to rendertargets from last frame as they're stale
5147         r_fb.rt_screen = NULL;
5148         r_fb.rt_bloom = NULL;
5149
5150         switch (vid.renderpath)
5151         {
5152         case RENDERPATH_GL32:
5153                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5154                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5155                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5156                 break;
5157         case RENDERPATH_GLES2:
5158                 r_fb.usedepthtextures = false;
5159                 break;
5160         }
5161
5162         if (r_viewscale_fpsscaling.integer)
5163         {
5164                 double actualframetime;
5165                 double targetframetime;
5166                 double adjust;
5167                 actualframetime = r_refdef.lastdrawscreentime;
5168                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5169                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5170                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5171                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5172                 {
5173                         if (adjust > 0)
5174                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5175                         else
5176                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5177                 }
5178                 viewscalefpsadjusted += adjust;
5179                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5180         }
5181         else
5182                 viewscalefpsadjusted = 1.0f;
5183
5184         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5185         if (vid.samples)
5186                 scale *= sqrt(vid.samples); // supersampling
5187         scale = bound(0.03125f, scale, 4.0f);
5188         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5189         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5190         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5191         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5192
5193         // set bloomwidth and bloomheight to the bloom resolution that will be
5194         // used (often less than the screen resolution for faster rendering)
5195         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5196         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5197         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5198         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5199         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5200
5201         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))
5202         {
5203                 Cvar_SetValueQuick(&r_bloom, 0);
5204                 Cvar_SetValueQuick(&r_motionblur, 0);
5205                 Cvar_SetValueQuick(&r_damageblur, 0);
5206         }
5207         if (!r_bloom.integer)
5208                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5209
5210         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5211         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5212         {
5213                 if (r_fb.ghosttexture)
5214                         R_FreeTexture(r_fb.ghosttexture);
5215                 r_fb.ghosttexture = NULL;
5216
5217                 r_fb.screentexturewidth = screentexturewidth;
5218                 r_fb.screentextureheight = screentextureheight;
5219                 r_fb.textype = textype;
5220
5221                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5222                 {
5223                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5224                                 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);
5225                         r_fb.ghosttexture_valid = false;
5226                 }
5227         }
5228
5229         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5230
5231         r_refdef.view.clear = true;
5232 }
5233
5234 static void R_Bloom_MakeTexture(void)
5235 {
5236         int x, range, dir;
5237         float xoffset, yoffset, r, brighten;
5238         float colorscale = r_bloom_colorscale.value;
5239         r_viewport_t bloomviewport;
5240         r_rendertarget_t *prev, *cur;
5241         textype_t textype = r_fb.rt_screen->colortextype[0];
5242
5243         r_refdef.stats[r_stat_bloom]++;
5244
5245         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5246
5247         // scale down screen texture to the bloom texture size
5248         CHECKGLERROR
5249         prev = r_fb.rt_screen;
5250         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5251         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5252         R_SetViewport(&bloomviewport);
5253         GL_CullFace(GL_NONE);
5254         GL_DepthTest(false);
5255         GL_BlendFunc(GL_ONE, GL_ZERO);
5256         GL_Color(colorscale, colorscale, colorscale, 1);
5257         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5258         // TODO: do boxfilter scale-down in shader?
5259         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5260         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5261         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5262         // we now have a properly scaled bloom image
5263
5264         // multiply bloom image by itself as many times as desired to darken it
5265         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5266         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5267         {
5268                 prev = cur;
5269                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5270                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5271                 x *= 2;
5272                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5273                 if(x <= 2)
5274                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5275                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5276                 GL_Color(1,1,1,1); // no fix factor supported here
5277                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5278                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5279                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5280                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5281         }
5282         CHECKGLERROR
5283
5284         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5285         brighten = r_bloom_brighten.value;
5286         brighten = sqrt(brighten);
5287         if(range >= 1)
5288                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5289
5290         for (dir = 0;dir < 2;dir++)
5291         {
5292                 prev = cur;
5293                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5294                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5295                 // blend on at multiple vertical offsets to achieve a vertical blur
5296                 // TODO: do offset blends using GLSL
5297                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5298                 CHECKGLERROR
5299                 GL_BlendFunc(GL_ONE, GL_ZERO);
5300                 CHECKGLERROR
5301                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5302                 CHECKGLERROR
5303                 for (x = -range;x <= range;x++)
5304                 {
5305                         if (!dir){xoffset = 0;yoffset = x;}
5306                         else {xoffset = x;yoffset = 0;}
5307                         xoffset /= (float)prev->texturewidth;
5308                         yoffset /= (float)prev->textureheight;
5309                         // compute a texcoord array with the specified x and y offset
5310                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5311                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5312                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5313                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5314                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5315                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5316                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5317                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5318                         // this r value looks like a 'dot' particle, fading sharply to
5319                         // black at the edges
5320                         // (probably not realistic but looks good enough)
5321                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5322                         //r = brighten/(range*2+1);
5323                         r = brighten / (range * 2 + 1);
5324                         if(range >= 1)
5325                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5326                         if (r <= 0)
5327                                 continue;
5328                         CHECKGLERROR
5329                         GL_Color(r, r, r, 1);
5330                         CHECKGLERROR
5331                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5332                         CHECKGLERROR
5333                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5334                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5335                         CHECKGLERROR
5336                         GL_BlendFunc(GL_ONE, GL_ONE);
5337                         CHECKGLERROR
5338                 }
5339         }
5340
5341         // now we have the bloom image, so keep track of it
5342         r_fb.rt_bloom = cur;
5343 }
5344
5345 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5346 {
5347         uint64_t permutation;
5348         float uservecs[4][4];
5349         rtexture_t *viewtexture;
5350         rtexture_t *bloomtexture;
5351
5352         R_EntityMatrix(&identitymatrix);
5353
5354         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5355         {
5356                 // declare variables
5357                 float blur_factor, blur_mouseaccel, blur_velocity;
5358                 static float blur_average; 
5359                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5360
5361                 // set a goal for the factoring
5362                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5363                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5364                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5365                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5366                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5367                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5368
5369                 // from the goal, pick an averaged value between goal and last value
5370                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5371                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5372
5373                 // enforce minimum amount of blur 
5374                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5375
5376                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5377
5378                 // calculate values into a standard alpha
5379                 cl.motionbluralpha = 1 - exp(-
5380                                 (
5381                                         (r_motionblur.value * blur_factor / 80)
5382                                         +
5383                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5384                                 )
5385                                 /
5386                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5387                                 );
5388
5389                 // randomization for the blur value to combat persistent ghosting
5390                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5391                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5392
5393                 // apply the blur
5394                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5395                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5396                 {
5397                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5398                         GL_Color(1, 1, 1, cl.motionbluralpha);
5399                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5400                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5401                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5402                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5403                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5404                 }
5405
5406                 // updates old view angles for next pass
5407                 VectorCopy(cl.viewangles, blur_oldangles);
5408
5409                 // copy view into the ghost texture
5410                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5411                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5412                 r_fb.ghosttexture_valid = true;
5413         }
5414
5415         if (r_fb.bloomwidth)
5416         {
5417                 // make the bloom texture
5418                 R_Bloom_MakeTexture();
5419         }
5420
5421 #if _MSC_VER >= 1400
5422 #define sscanf sscanf_s
5423 #endif
5424         memset(uservecs, 0, sizeof(uservecs));
5425         if (r_glsl_postprocess_uservec1_enable.integer)
5426                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5427         if (r_glsl_postprocess_uservec2_enable.integer)
5428                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5429         if (r_glsl_postprocess_uservec3_enable.integer)
5430                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5431         if (r_glsl_postprocess_uservec4_enable.integer)
5432                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5433
5434         // render to the screen fbo
5435         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5436         GL_Color(1, 1, 1, 1);
5437         GL_BlendFunc(GL_ONE, GL_ZERO);
5438
5439         viewtexture = r_fb.rt_screen->colortexture[0];
5440         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5441
5442         if (r_rendertarget_debug.integer >= 0)
5443         {
5444                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5445                 if (rt && rt->colortexture[0])
5446                 {
5447                         viewtexture = rt->colortexture[0];
5448                         bloomtexture = NULL;
5449                 }
5450         }
5451
5452         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5453         switch(vid.renderpath)
5454         {
5455         case RENDERPATH_GL32:
5456         case RENDERPATH_GLES2:
5457                 permutation =
5458                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5459                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5460                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5461                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5462                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5463                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5464                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5465                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5466                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5467                 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]);
5468                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5469                 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]);
5470                 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]);
5471                 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]);
5472                 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]);
5473                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5474                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5475                 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);
5476                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5477                 break;
5478         }
5479         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5480         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5481 }
5482
5483 matrix4x4_t r_waterscrollmatrix;
5484
5485 void R_UpdateFog(void)
5486 {
5487         // Nehahra fog
5488         if (gamemode == GAME_NEHAHRA)
5489         {
5490                 if (gl_fogenable.integer)
5491                 {
5492                         r_refdef.oldgl_fogenable = true;
5493                         r_refdef.fog_density = gl_fogdensity.value;
5494                         r_refdef.fog_red = gl_fogred.value;
5495                         r_refdef.fog_green = gl_foggreen.value;
5496                         r_refdef.fog_blue = gl_fogblue.value;
5497                         r_refdef.fog_alpha = 1;
5498                         r_refdef.fog_start = 0;
5499                         r_refdef.fog_end = gl_skyclip.value;
5500                         r_refdef.fog_height = 1<<30;
5501                         r_refdef.fog_fadedepth = 128;
5502                 }
5503                 else if (r_refdef.oldgl_fogenable)
5504                 {
5505                         r_refdef.oldgl_fogenable = false;
5506                         r_refdef.fog_density = 0;
5507                         r_refdef.fog_red = 0;
5508                         r_refdef.fog_green = 0;
5509                         r_refdef.fog_blue = 0;
5510                         r_refdef.fog_alpha = 0;
5511                         r_refdef.fog_start = 0;
5512                         r_refdef.fog_end = 0;
5513                         r_refdef.fog_height = 1<<30;
5514                         r_refdef.fog_fadedepth = 128;
5515                 }
5516         }
5517
5518         // fog parms
5519         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5520         r_refdef.fog_start = max(0, r_refdef.fog_start);
5521         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5522
5523         if (r_refdef.fog_density && r_drawfog.integer)
5524         {
5525                 r_refdef.fogenabled = true;
5526                 // this is the point where the fog reaches 0.9986 alpha, which we
5527                 // consider a good enough cutoff point for the texture
5528                 // (0.9986 * 256 == 255.6)
5529                 if (r_fog_exp2.integer)
5530                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5531                 else
5532                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5533                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5534                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5535                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5536                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5537                         R_BuildFogHeightTexture();
5538                 // fog color was already set
5539                 // update the fog texture
5540                 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)
5541                         R_BuildFogTexture();
5542                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5543                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5544         }
5545         else
5546                 r_refdef.fogenabled = false;
5547
5548         // fog color
5549         if (r_refdef.fog_density)
5550         {
5551                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5552                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5553                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5554
5555                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5556                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5557                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5558                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5559
5560                 {
5561                         vec3_t fogvec;
5562                         VectorCopy(r_refdef.fogcolor, fogvec);
5563                         //   color.rgb *= ContrastBoost * SceneBrightness;
5564                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5565                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5566                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5567                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5568                 }
5569         }
5570 }
5571
5572 void R_UpdateVariables(void)
5573 {
5574         R_Textures_Frame();
5575
5576         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5577
5578         r_refdef.farclip = r_farclip_base.value;
5579         if (r_refdef.scene.worldmodel)
5580                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5581         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5582
5583         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5584                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5585         r_refdef.polygonfactor = 0;
5586         r_refdef.polygonoffset = 0;
5587
5588         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5589         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5590         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5591         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5592         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5593         if (r_refdef.scene.worldmodel)
5594         {
5595                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5596         }
5597         if (r_showsurfaces.integer)
5598         {
5599                 r_refdef.scene.rtworld = false;
5600                 r_refdef.scene.rtworldshadows = false;
5601                 r_refdef.scene.rtdlight = false;
5602                 r_refdef.scene.rtdlightshadows = false;
5603                 r_refdef.scene.lightmapintensity = 0;
5604         }
5605
5606         r_gpuskeletal = false;
5607         switch(vid.renderpath)
5608         {
5609         case RENDERPATH_GL32:
5610                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5611         case RENDERPATH_GLES2:
5612                 if(!vid_gammatables_trivial)
5613                 {
5614                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5615                         {
5616                                 // build GLSL gamma texture
5617 #define RAMPWIDTH 256
5618                                 unsigned short ramp[RAMPWIDTH * 3];
5619                                 unsigned char rampbgr[RAMPWIDTH][4];
5620                                 int i;
5621
5622                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5623
5624                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5625                                 for(i = 0; i < RAMPWIDTH; ++i)
5626                                 {
5627                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5628                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5629                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5630                                         rampbgr[i][3] = 0;
5631                                 }
5632                                 if (r_texture_gammaramps)
5633                                 {
5634                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5635                                 }
5636                                 else
5637                                 {
5638                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5639                                 }
5640                         }
5641                 }
5642                 else
5643                 {
5644                         // remove GLSL gamma texture
5645                 }
5646                 break;
5647         }
5648 }
5649
5650 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5651 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5652 /*
5653 ================
5654 R_SelectScene
5655 ================
5656 */
5657 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5658         if( scenetype != r_currentscenetype ) {
5659                 // store the old scenetype
5660                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5661                 r_currentscenetype = scenetype;
5662                 // move in the new scene
5663                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5664         }
5665 }
5666
5667 /*
5668 ================
5669 R_GetScenePointer
5670 ================
5671 */
5672 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5673 {
5674         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5675         if( scenetype == r_currentscenetype ) {
5676                 return &r_refdef.scene;
5677         } else {
5678                 return &r_scenes_store[ scenetype ];
5679         }
5680 }
5681
5682 static int R_SortEntities_Compare(const void *ap, const void *bp)
5683 {
5684         const entity_render_t *a = *(const entity_render_t **)ap;
5685         const entity_render_t *b = *(const entity_render_t **)bp;
5686
5687         // 1. compare model
5688         if(a->model < b->model)
5689                 return -1;
5690         if(a->model > b->model)
5691                 return +1;
5692
5693         // 2. compare skin
5694         // TODO possibly calculate the REAL skinnum here first using
5695         // skinscenes?
5696         if(a->skinnum < b->skinnum)
5697                 return -1;
5698         if(a->skinnum > b->skinnum)
5699                 return +1;
5700
5701         // everything we compared is equal
5702         return 0;
5703 }
5704 static void R_SortEntities(void)
5705 {
5706         // below or equal 2 ents, sorting never gains anything
5707         if(r_refdef.scene.numentities <= 2)
5708                 return;
5709         // sort
5710         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5711 }
5712
5713 /*
5714 ================
5715 R_RenderView
5716 ================
5717 */
5718 extern cvar_t r_shadow_bouncegrid;
5719 extern cvar_t v_isometric;
5720 extern void V_MakeViewIsometric(void);
5721 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5722 {
5723         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5724         int viewfbo = 0;
5725         rtexture_t *viewdepthtexture = NULL;
5726         rtexture_t *viewcolortexture = NULL;
5727         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5728
5729         // finish any 2D rendering that was queued
5730         DrawQ_Finish();
5731
5732         if (r_timereport_active)
5733                 R_TimeReport("start");
5734         r_textureframe++; // used only by R_GetCurrentTexture
5735         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5736
5737         if(R_CompileShader_CheckStaticParms())
5738                 R_GLSL_Restart_f(&cmd_client);
5739
5740         if (!r_drawentities.integer)
5741                 r_refdef.scene.numentities = 0;
5742         else if (r_sortentities.integer)
5743                 R_SortEntities();
5744
5745         R_AnimCache_ClearCache();
5746
5747         /* adjust for stereo display */
5748         if(R_Stereo_Active())
5749         {
5750                 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);
5751                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5752         }
5753
5754         if (r_refdef.view.isoverlay)
5755         {
5756                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5757                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5758                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5759                 R_TimeReport("depthclear");
5760
5761                 r_refdef.view.showdebug = false;
5762
5763                 r_fb.water.enabled = false;
5764                 r_fb.water.numwaterplanes = 0;
5765
5766                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5767
5768                 r_refdef.view.matrix = originalmatrix;
5769
5770                 CHECKGLERROR
5771                 return;
5772         }
5773
5774         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5775         {
5776                 r_refdef.view.matrix = originalmatrix;
5777                 return;
5778         }
5779
5780         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5781         if (v_isometric.integer && r_refdef.view.ismain)
5782                 V_MakeViewIsometric();
5783
5784         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5785
5786         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5787                 // in sRGB fallback, behave similar to true sRGB: convert this
5788                 // value from linear to sRGB
5789                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5790
5791         R_RenderView_UpdateViewVectors();
5792
5793         R_Shadow_UpdateWorldLightSelection();
5794
5795         // this will set up r_fb.rt_screen
5796         R_Bloom_StartFrame();
5797
5798         // apply bloom brightness offset
5799         if(r_fb.rt_bloom)
5800                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5801
5802         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5803         if (r_fb.rt_screen)
5804         {
5805                 viewfbo = r_fb.rt_screen->fbo;
5806                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5807                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5808                 viewx = 0;
5809                 viewy = 0;
5810                 viewwidth = r_fb.rt_screen->texturewidth;
5811                 viewheight = r_fb.rt_screen->textureheight;
5812         }
5813
5814         R_Water_StartFrame(viewwidth, viewheight);
5815
5816         CHECKGLERROR
5817         if (r_timereport_active)
5818                 R_TimeReport("viewsetup");
5819
5820         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5821
5822         // clear the whole fbo every frame - otherwise the driver will consider
5823         // it to be an inter-frame texture and stall in multi-gpu configurations
5824         if (r_fb.rt_screen)
5825                 GL_ScissorTest(false);
5826         R_ClearScreen(r_refdef.fogenabled);
5827         if (r_timereport_active)
5828                 R_TimeReport("viewclear");
5829
5830         r_refdef.view.clear = true;
5831
5832         r_refdef.view.showdebug = true;
5833
5834         R_View_Update();
5835         if (r_timereport_active)
5836                 R_TimeReport("visibility");
5837
5838         R_AnimCache_CacheVisibleEntities();
5839         if (r_timereport_active)
5840                 R_TimeReport("animcache");
5841
5842         R_Shadow_UpdateBounceGridTexture();
5843         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5844
5845         r_fb.water.numwaterplanes = 0;
5846         if (r_fb.water.enabled)
5847                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5848
5849         // for the actual view render we use scissoring a fair amount, so scissor
5850         // test needs to be on
5851         if (r_fb.rt_screen)
5852                 GL_ScissorTest(true);
5853         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5854         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5855         r_fb.water.numwaterplanes = 0;
5856
5857         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5858         GL_ScissorTest(false);
5859
5860         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5861         if (r_timereport_active)
5862                 R_TimeReport("blendview");
5863
5864         r_refdef.view.matrix = originalmatrix;
5865
5866         CHECKGLERROR
5867
5868         // go back to 2d rendering
5869         DrawQ_Start();
5870 }
5871
5872 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5873 {
5874         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5875         {
5876                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5877                 if (r_timereport_active)
5878                         R_TimeReport("waterworld");
5879         }
5880
5881         // don't let sound skip if going slow
5882         if (r_refdef.scene.extraupdate)
5883                 S_ExtraUpdate ();
5884
5885         R_DrawModelsAddWaterPlanes();
5886         if (r_timereport_active)
5887                 R_TimeReport("watermodels");
5888
5889         if (r_fb.water.numwaterplanes)
5890         {
5891                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5892                 if (r_timereport_active)
5893                         R_TimeReport("waterscenes");
5894         }
5895 }
5896
5897 extern cvar_t cl_locs_show;
5898 static void R_DrawLocs(void);
5899 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5900 static void R_DrawModelDecals(void);
5901 extern qboolean r_shadow_usingdeferredprepass;
5902 extern int r_shadow_shadowmapatlas_modelshadows_size;
5903 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5904 {
5905         qboolean shadowmapping = false;
5906
5907         if (r_timereport_active)
5908                 R_TimeReport("beginscene");
5909
5910         r_refdef.stats[r_stat_renders]++;
5911
5912         R_UpdateFog();
5913
5914         // don't let sound skip if going slow
5915         if (r_refdef.scene.extraupdate)
5916                 S_ExtraUpdate ();
5917
5918         R_MeshQueue_BeginScene();
5919
5920         R_SkyStartFrame();
5921
5922         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);
5923
5924         if (r_timereport_active)
5925                 R_TimeReport("skystartframe");
5926
5927         if (cl.csqc_vidvars.drawworld)
5928         {
5929                 // don't let sound skip if going slow
5930                 if (r_refdef.scene.extraupdate)
5931                         S_ExtraUpdate ();
5932
5933                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5934                 {
5935                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5936                         if (r_timereport_active)
5937                                 R_TimeReport("worldsky");
5938                 }
5939
5940                 if (R_DrawBrushModelsSky() && r_timereport_active)
5941                         R_TimeReport("bmodelsky");
5942
5943                 if (skyrendermasked && skyrenderlater)
5944                 {
5945                         // we have to force off the water clipping plane while rendering sky
5946                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5947                         R_Sky();
5948                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5949                         if (r_timereport_active)
5950                                 R_TimeReport("sky");
5951                 }
5952         }
5953
5954         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5955         r_shadow_viewfbo = viewfbo;
5956         r_shadow_viewdepthtexture = viewdepthtexture;
5957         r_shadow_viewcolortexture = viewcolortexture;
5958         r_shadow_viewx = viewx;
5959         r_shadow_viewy = viewy;
5960         r_shadow_viewwidth = viewwidth;
5961         r_shadow_viewheight = viewheight;
5962
5963         R_Shadow_PrepareModelShadows();
5964         R_Shadow_PrepareLights();
5965         if (r_timereport_active)
5966                 R_TimeReport("preparelights");
5967
5968         // render all the shadowmaps that will be used for this view
5969         shadowmapping = R_Shadow_ShadowMappingEnabled();
5970         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5971         {
5972                 R_Shadow_DrawShadowMaps();
5973                 if (r_timereport_active)
5974                         R_TimeReport("shadowmaps");
5975         }
5976
5977         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5978         if (r_shadow_usingdeferredprepass)
5979                 R_Shadow_DrawPrepass();
5980
5981         // now we begin the forward pass of the view render
5982         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5983         {
5984                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5985                 if (r_timereport_active)
5986                         R_TimeReport("worlddepth");
5987         }
5988         if (r_depthfirst.integer >= 2)
5989         {
5990                 R_DrawModelsDepth();
5991                 if (r_timereport_active)
5992                         R_TimeReport("modeldepth");
5993         }
5994
5995         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5996         {
5997                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5998                 if (r_timereport_active)
5999                         R_TimeReport("world");
6000         }
6001
6002         // don't let sound skip if going slow
6003         if (r_refdef.scene.extraupdate)
6004                 S_ExtraUpdate ();
6005
6006         R_DrawModels();
6007         if (r_timereport_active)
6008                 R_TimeReport("models");
6009
6010         // don't let sound skip if going slow
6011         if (r_refdef.scene.extraupdate)
6012                 S_ExtraUpdate ();
6013
6014         if (!r_shadow_usingdeferredprepass)
6015         {
6016                 R_Shadow_DrawLights();
6017                 if (r_timereport_active)
6018                         R_TimeReport("rtlights");
6019         }
6020
6021         // don't let sound skip if going slow
6022         if (r_refdef.scene.extraupdate)
6023                 S_ExtraUpdate ();
6024
6025         if (cl.csqc_vidvars.drawworld)
6026         {
6027                 R_DrawModelDecals();
6028                 if (r_timereport_active)
6029                         R_TimeReport("modeldecals");
6030
6031                 R_DrawParticles();
6032                 if (r_timereport_active)
6033                         R_TimeReport("particles");
6034
6035                 R_DrawExplosions();
6036                 if (r_timereport_active)
6037                         R_TimeReport("explosions");
6038         }
6039
6040         if (r_refdef.view.showdebug)
6041         {
6042                 if (cl_locs_show.integer)
6043                 {
6044                         R_DrawLocs();
6045                         if (r_timereport_active)
6046                                 R_TimeReport("showlocs");
6047                 }
6048
6049                 if (r_drawportals.integer)
6050                 {
6051                         R_DrawPortals();
6052                         if (r_timereport_active)
6053                                 R_TimeReport("portals");
6054                 }
6055
6056                 if (r_showbboxes_client.value > 0)
6057                 {
6058                         R_DrawEntityBBoxes(CLVM_prog);
6059                         if (r_timereport_active)
6060                                 R_TimeReport("clbboxes");
6061                 }
6062                 if (r_showbboxes.value > 0)
6063                 {
6064                         R_DrawEntityBBoxes(SVVM_prog);
6065                         if (r_timereport_active)
6066                                 R_TimeReport("svbboxes");
6067                 }
6068         }
6069
6070         if (r_transparent.integer)
6071         {
6072                 R_MeshQueue_RenderTransparent();
6073                 if (r_timereport_active)
6074                         R_TimeReport("drawtrans");
6075         }
6076
6077         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))
6078         {
6079                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6080                 if (r_timereport_active)
6081                         R_TimeReport("worlddebug");
6082                 R_DrawModelsDebug();
6083                 if (r_timereport_active)
6084                         R_TimeReport("modeldebug");
6085         }
6086
6087         if (cl.csqc_vidvars.drawworld)
6088         {
6089                 R_Shadow_DrawCoronas();
6090                 if (r_timereport_active)
6091                         R_TimeReport("coronas");
6092         }
6093
6094         // don't let sound skip if going slow
6095         if (r_refdef.scene.extraupdate)
6096                 S_ExtraUpdate ();
6097 }
6098
6099 static const unsigned short bboxelements[36] =
6100 {
6101         5, 1, 3, 5, 3, 7,
6102         6, 2, 0, 6, 0, 4,
6103         7, 3, 2, 7, 2, 6,
6104         4, 0, 1, 4, 1, 5,
6105         4, 5, 7, 4, 7, 6,
6106         1, 0, 2, 1, 2, 3,
6107 };
6108
6109 #define BBOXEDGES 13
6110 static const float bboxedges[BBOXEDGES][6] = 
6111 {
6112         // whole box
6113         { 0, 0, 0, 1, 1, 1 },
6114         // bottom edges
6115         { 0, 0, 0, 0, 1, 0 },
6116         { 0, 0, 0, 1, 0, 0 },
6117         { 0, 1, 0, 1, 1, 0 },
6118         { 1, 0, 0, 1, 1, 0 },
6119         // top edges
6120         { 0, 0, 1, 0, 1, 1 },
6121         { 0, 0, 1, 1, 0, 1 },
6122         { 0, 1, 1, 1, 1, 1 },
6123         { 1, 0, 1, 1, 1, 1 },
6124         // vertical edges
6125         { 0, 0, 0, 0, 0, 1 },
6126         { 1, 0, 0, 1, 0, 1 },
6127         { 0, 1, 0, 0, 1, 1 },
6128         { 1, 1, 0, 1, 1, 1 },
6129 };
6130
6131 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6132 {
6133         int numvertices = BBOXEDGES * 8;
6134         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6135         int numtriangles = BBOXEDGES * 12;
6136         unsigned short elements[BBOXEDGES * 36];
6137         int i, edge;
6138         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6139
6140         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6141
6142         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6143         GL_DepthMask(false);
6144         GL_DepthRange(0, 1);
6145         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6146
6147         for (edge = 0; edge < BBOXEDGES; edge++)
6148         {
6149                 for (i = 0; i < 3; i++)
6150                 {
6151                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6152                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6153                 }
6154                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6155                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6156                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6157                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6158                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6159                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6160                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6161                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6162                 for (i = 0; i < 36; i++)
6163                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6164         }
6165         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6166         if (r_refdef.fogenabled)
6167         {
6168                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6169                 {
6170                         f1 = RSurf_FogVertex(v);
6171                         f2 = 1 - f1;
6172                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6173                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6174                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6175                 }
6176         }
6177         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6178         R_Mesh_ResetTextureState();
6179         R_SetupShader_Generic_NoTexture(false, false);
6180         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6181 }
6182
6183 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6184 {
6185         // hacky overloading of the parameters
6186         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6187         int i;
6188         float color[4];
6189         prvm_edict_t *edict;
6190
6191         GL_CullFace(GL_NONE);
6192         R_SetupShader_Generic_NoTexture(false, false);
6193
6194         for (i = 0;i < numsurfaces;i++)
6195         {
6196                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6197                 switch ((int)PRVM_serveredictfloat(edict, solid))
6198                 {
6199                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6200                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6201                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6202                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6203                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6204                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6205                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6206                 }
6207                 if (prog == CLVM_prog)
6208                         color[3] *= r_showbboxes_client.value;
6209                 else
6210                         color[3] *= r_showbboxes.value;
6211                 color[3] = bound(0, color[3], 1);
6212                 GL_DepthTest(!r_showdisabledepthtest.integer);
6213                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6214         }
6215 }
6216
6217 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6218 {
6219         int i;
6220         prvm_edict_t *edict;
6221         vec3_t center;
6222
6223         if (prog == NULL)
6224                 return;
6225
6226         for (i = 0; i < prog->num_edicts; i++)
6227         {
6228                 edict = PRVM_EDICT_NUM(i);
6229                 if (edict->priv.server->free)
6230                         continue;
6231                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6232                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6233                         continue;
6234                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6235                         continue;
6236                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6237                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6238         }
6239 }
6240
6241 static const int nomodelelement3i[24] =
6242 {
6243         5, 2, 0,
6244         5, 1, 2,
6245         5, 0, 3,
6246         5, 3, 1,
6247         0, 2, 4,
6248         2, 1, 4,
6249         3, 0, 4,
6250         1, 3, 4
6251 };
6252
6253 static const unsigned short nomodelelement3s[24] =
6254 {
6255         5, 2, 0,
6256         5, 1, 2,
6257         5, 0, 3,
6258         5, 3, 1,
6259         0, 2, 4,
6260         2, 1, 4,
6261         3, 0, 4,
6262         1, 3, 4
6263 };
6264
6265 static const float nomodelvertex3f[6*3] =
6266 {
6267         -16,   0,   0,
6268          16,   0,   0,
6269           0, -16,   0,
6270           0,  16,   0,
6271           0,   0, -16,
6272           0,   0,  16
6273 };
6274
6275 static const float nomodelcolor4f[6*4] =
6276 {
6277         0.0f, 0.0f, 0.5f, 1.0f,
6278         0.0f, 0.0f, 0.5f, 1.0f,
6279         0.0f, 0.5f, 0.0f, 1.0f,
6280         0.0f, 0.5f, 0.0f, 1.0f,
6281         0.5f, 0.0f, 0.0f, 1.0f,
6282         0.5f, 0.0f, 0.0f, 1.0f
6283 };
6284
6285 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6286 {
6287         int i;
6288         float f1, f2, *c;
6289         float color4f[6*4];
6290
6291         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);
6292
6293         // this is only called once per entity so numsurfaces is always 1, and
6294         // surfacelist is always {0}, so this code does not handle batches
6295
6296         if (rsurface.ent_flags & RENDER_ADDITIVE)
6297         {
6298                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6299                 GL_DepthMask(false);
6300         }
6301         else if (ent->alpha < 1)
6302         {
6303                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6304                 GL_DepthMask(false);
6305         }
6306         else
6307         {
6308                 GL_BlendFunc(GL_ONE, GL_ZERO);
6309                 GL_DepthMask(true);
6310         }
6311         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6312         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6313         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6314         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6315         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6316         for (i = 0, c = color4f;i < 6;i++, c += 4)
6317         {
6318                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6319                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6320                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6321                 c[3] *= ent->alpha;
6322         }
6323         if (r_refdef.fogenabled)
6324         {
6325                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6326                 {
6327                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6328                         f2 = 1 - f1;
6329                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6330                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6331                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6332                 }
6333         }
6334 //      R_Mesh_ResetTextureState();
6335         R_SetupShader_Generic_NoTexture(false, false);
6336         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6337         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6338 }
6339
6340 void R_DrawNoModel(entity_render_t *ent)
6341 {
6342         vec3_t org;
6343         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6344         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6345                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6346         else
6347                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6348 }
6349
6350 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6351 {
6352         vec3_t right1, right2, diff, normal;
6353
6354         VectorSubtract (org2, org1, normal);
6355
6356         // calculate 'right' vector for start
6357         VectorSubtract (r_refdef.view.origin, org1, diff);
6358         CrossProduct (normal, diff, right1);
6359         VectorNormalize (right1);
6360
6361         // calculate 'right' vector for end
6362         VectorSubtract (r_refdef.view.origin, org2, diff);
6363         CrossProduct (normal, diff, right2);
6364         VectorNormalize (right2);
6365
6366         vert[ 0] = org1[0] + width * right1[0];
6367         vert[ 1] = org1[1] + width * right1[1];
6368         vert[ 2] = org1[2] + width * right1[2];
6369         vert[ 3] = org1[0] - width * right1[0];
6370         vert[ 4] = org1[1] - width * right1[1];
6371         vert[ 5] = org1[2] - width * right1[2];
6372         vert[ 6] = org2[0] - width * right2[0];
6373         vert[ 7] = org2[1] - width * right2[1];
6374         vert[ 8] = org2[2] - width * right2[2];
6375         vert[ 9] = org2[0] + width * right2[0];
6376         vert[10] = org2[1] + width * right2[1];
6377         vert[11] = org2[2] + width * right2[2];
6378 }
6379
6380 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)
6381 {
6382         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6383         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6384         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6385         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6386         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6387         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6388         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6389         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6390         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6391         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6392         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6393         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6394 }
6395
6396 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6397 {
6398         int i;
6399         float *vertex3f;
6400         float v[3];
6401         VectorSet(v, x, y, z);
6402         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6403                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6404                         break;
6405         if (i == mesh->numvertices)
6406         {
6407                 if (mesh->numvertices < mesh->maxvertices)
6408                 {
6409                         VectorCopy(v, vertex3f);
6410                         mesh->numvertices++;
6411                 }
6412                 return mesh->numvertices;
6413         }
6414         else
6415                 return i;
6416 }
6417
6418 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6419 {
6420         int i;
6421         int *e, element[3];
6422         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6423         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6424         e = mesh->element3i + mesh->numtriangles * 3;
6425         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6426         {
6427                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6428                 if (mesh->numtriangles < mesh->maxtriangles)
6429                 {
6430                         *e++ = element[0];
6431                         *e++ = element[1];
6432                         *e++ = element[2];
6433                         mesh->numtriangles++;
6434                 }
6435                 element[1] = element[2];
6436         }
6437 }
6438
6439 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6440 {
6441         int i;
6442         int *e, element[3];
6443         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6444         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6445         e = mesh->element3i + mesh->numtriangles * 3;
6446         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6447         {
6448                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6449                 if (mesh->numtriangles < mesh->maxtriangles)
6450                 {
6451                         *e++ = element[0];
6452                         *e++ = element[1];
6453                         *e++ = element[2];
6454                         mesh->numtriangles++;
6455                 }
6456                 element[1] = element[2];
6457         }
6458 }
6459
6460 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6461 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6462 {
6463         int planenum, planenum2;
6464         int w;
6465         int tempnumpoints;
6466         mplane_t *plane, *plane2;
6467         double maxdist;
6468         double temppoints[2][256*3];
6469         // figure out how large a bounding box we need to properly compute this brush
6470         maxdist = 0;
6471         for (w = 0;w < numplanes;w++)
6472                 maxdist = max(maxdist, fabs(planes[w].dist));
6473         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6474         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6475         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6476         {
6477                 w = 0;
6478                 tempnumpoints = 4;
6479                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6480                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6481                 {
6482                         if (planenum2 == planenum)
6483                                 continue;
6484                         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);
6485                         w = !w;
6486                 }
6487                 if (tempnumpoints < 3)
6488                         continue;
6489                 // generate elements forming a triangle fan for this polygon
6490                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6491         }
6492 }
6493
6494 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6495 {
6496         if(parms[0] == 0 && parms[1] == 0)
6497                 return false;
6498         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6499                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6500                         return false;
6501         return true;
6502 }
6503
6504 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6505 {
6506         double index, f;
6507         index = parms[2] + rsurface.shadertime * parms[3];
6508         index -= floor(index);
6509         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6510         {
6511         default:
6512         case Q3WAVEFUNC_NONE:
6513         case Q3WAVEFUNC_NOISE:
6514         case Q3WAVEFUNC_COUNT:
6515                 f = 0;
6516                 break;
6517         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6518         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6519         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6520         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6521         case Q3WAVEFUNC_TRIANGLE:
6522                 index *= 4;
6523                 f = index - floor(index);
6524                 if (index < 1)
6525                 {
6526                         // f = f;
6527                 }
6528                 else if (index < 2)
6529                         f = 1 - f;
6530                 else if (index < 3)
6531                         f = -f;
6532                 else
6533                         f = -(1 - f);
6534                 break;
6535         }
6536         f = parms[0] + parms[1] * f;
6537         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6538                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6539         return (float) f;
6540 }
6541
6542 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6543 {
6544         int w, h, idx;
6545         float shadertime;
6546         float f;
6547         float offsetd[2];
6548         float tcmat[12];
6549         matrix4x4_t matrix, temp;
6550         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6551         // it's better to have one huge fixup every 9 hours than gradual
6552         // degradation over time which looks consistently bad after many hours.
6553         //
6554         // tcmod scroll in particular suffers from this degradation which can't be
6555         // effectively worked around even with floor() tricks because we don't
6556         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6557         // a workaround involving floor() would be incorrect anyway...
6558         shadertime = rsurface.shadertime;
6559         if (shadertime >= 32768.0f)
6560                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6561         switch(tcmod->tcmod)
6562         {
6563                 case Q3TCMOD_COUNT:
6564                 case Q3TCMOD_NONE:
6565                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6566                                 matrix = r_waterscrollmatrix;
6567                         else
6568                                 matrix = identitymatrix;
6569                         break;
6570                 case Q3TCMOD_ENTITYTRANSLATE:
6571                         // this is used in Q3 to allow the gamecode to control texcoord
6572                         // scrolling on the entity, which is not supported in darkplaces yet.
6573                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6574                         break;
6575                 case Q3TCMOD_ROTATE:
6576                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6577                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6578                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6579                         break;
6580                 case Q3TCMOD_SCALE:
6581                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6582                         break;
6583                 case Q3TCMOD_SCROLL:
6584                         // this particular tcmod is a "bug for bug" compatible one with regards to
6585                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6586                         // specifically did the wrapping and so we must mimic that...
6587                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6588                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6589                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6590                         break;
6591                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6592                         w = (int) tcmod->parms[0];
6593                         h = (int) tcmod->parms[1];
6594                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6595                         f = f - floor(f);
6596                         idx = (int) floor(f * w * h);
6597                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6598                         break;
6599                 case Q3TCMOD_STRETCH:
6600                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6601                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6602                         break;
6603                 case Q3TCMOD_TRANSFORM:
6604                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6605                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6606                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6607                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6608                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6609                         break;
6610                 case Q3TCMOD_TURBULENT:
6611                         // this is handled in the RSurf_PrepareVertices function
6612                         matrix = identitymatrix;
6613                         break;
6614         }
6615         temp = *texmatrix;
6616         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6617 }
6618
6619 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6620 {
6621         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6622         char name[MAX_QPATH];
6623         skinframe_t *skinframe;
6624         unsigned char pixels[296*194];
6625         strlcpy(cache->name, skinname, sizeof(cache->name));
6626         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6627         if (developer_loading.integer)
6628                 Con_Printf("loading %s\n", name);
6629         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6630         if (!skinframe || !skinframe->base)
6631         {
6632                 unsigned char *f;
6633                 fs_offset_t filesize;
6634                 skinframe = NULL;
6635                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6636                 if (f)
6637                 {
6638                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6639                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6640                         Mem_Free(f);
6641                 }
6642         }
6643         cache->skinframe = skinframe;
6644 }
6645
6646 texture_t *R_GetCurrentTexture(texture_t *t)
6647 {
6648         int i, q;
6649         const entity_render_t *ent = rsurface.entity;
6650         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6651         q3shaderinfo_layer_tcmod_t *tcmod;
6652         float specularscale = 0.0f;
6653
6654         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6655                 return t->currentframe;
6656         t->update_lastrenderframe = r_textureframe;
6657         t->update_lastrenderentity = (void *)ent;
6658
6659         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6660                 t->camera_entity = ent->entitynumber;
6661         else
6662                 t->camera_entity = 0;
6663
6664         // switch to an alternate material if this is a q1bsp animated material
6665         {
6666                 texture_t *texture = t;
6667                 int s = rsurface.ent_skinnum;
6668                 if ((unsigned int)s >= (unsigned int)model->numskins)
6669                         s = 0;
6670                 if (model->skinscenes)
6671                 {
6672                         if (model->skinscenes[s].framecount > 1)
6673                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6674                         else
6675                                 s = model->skinscenes[s].firstframe;
6676                 }
6677                 if (s > 0)
6678                         t = t + s * model->num_surfaces;
6679                 if (t->animated)
6680                 {
6681                         // use an alternate animation if the entity's frame is not 0,
6682                         // and only if the texture has an alternate animation
6683                         if (t->animated == 2) // q2bsp
6684                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6685                         else if (rsurface.ent_alttextures && t->anim_total[1])
6686                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6687                         else
6688                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6689                 }
6690                 texture->currentframe = t;
6691         }
6692
6693         // update currentskinframe to be a qw skin or animation frame
6694         if (rsurface.ent_qwskin >= 0)
6695         {
6696                 i = rsurface.ent_qwskin;
6697                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6698                 {
6699                         r_qwskincache_size = cl.maxclients;
6700                         if (r_qwskincache)
6701                                 Mem_Free(r_qwskincache);
6702                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6703                 }
6704                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6705                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6706                 t->currentskinframe = r_qwskincache[i].skinframe;
6707                 if (t->materialshaderpass && t->currentskinframe == NULL)
6708                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6709         }
6710         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6711                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6712         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6713                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6714
6715         t->currentmaterialflags = t->basematerialflags;
6716         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6717         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6718                 t->currentalpha *= r_wateralpha.value;
6719         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6720                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6721         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6722                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6723
6724         // decide on which type of lighting to use for this surface
6725         if (rsurface.entity->render_modellight_forced)
6726                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6727         if (rsurface.entity->render_rtlight_disabled)
6728                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6729         if (rsurface.entity->render_lightgrid)
6730                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6731         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6732         {
6733                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6734                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6735                 for (q = 0; q < 3; q++)
6736                 {
6737                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6738                         t->render_modellight_lightdir_world[q] = q == 2;
6739                         t->render_modellight_lightdir_local[q] = q == 2;
6740                         t->render_modellight_ambient[q] = 1;
6741                         t->render_modellight_diffuse[q] = 0;
6742                         t->render_modellight_specular[q] = 0;
6743                         t->render_lightmap_ambient[q] = 0;
6744                         t->render_lightmap_diffuse[q] = 0;
6745                         t->render_lightmap_specular[q] = 0;
6746                         t->render_rtlight_diffuse[q] = 0;
6747                         t->render_rtlight_specular[q] = 0;
6748                 }
6749         }
6750         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6751         {
6752                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6753                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6754                 for (q = 0; q < 3; q++)
6755                 {
6756                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6757                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6758                         t->render_modellight_lightdir_world[q] = q == 2;
6759                         t->render_modellight_lightdir_local[q] = q == 2;
6760                         t->render_modellight_diffuse[q] = 0;
6761                         t->render_modellight_specular[q] = 0;
6762                         t->render_lightmap_ambient[q] = 0;
6763                         t->render_lightmap_diffuse[q] = 0;
6764                         t->render_lightmap_specular[q] = 0;
6765                         t->render_rtlight_diffuse[q] = 0;
6766                         t->render_rtlight_specular[q] = 0;
6767                 }
6768         }
6769         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6770         {
6771                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6772                 for (q = 0; q < 3; q++)
6773                 {
6774                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6775                         t->render_modellight_lightdir_world[q] = q == 2;
6776                         t->render_modellight_lightdir_local[q] = q == 2;
6777                         t->render_modellight_ambient[q] = 0;
6778                         t->render_modellight_diffuse[q] = 0;
6779                         t->render_modellight_specular[q] = 0;
6780                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6781                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6782                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6783                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6784                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6785                 }
6786         }
6787         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6788         {
6789                 // ambient + single direction light (modellight)
6790                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6791                 for (q = 0; q < 3; q++)
6792                 {
6793                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6794                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6795                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6796                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6797                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6798                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6799                         t->render_lightmap_ambient[q] = 0;
6800                         t->render_lightmap_diffuse[q] = 0;
6801                         t->render_lightmap_specular[q] = 0;
6802                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6803                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6804                 }
6805         }
6806         else
6807         {
6808                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6809                 for (q = 0; q < 3; q++)
6810                 {
6811                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6812                         t->render_modellight_lightdir_world[q] = q == 2;
6813                         t->render_modellight_lightdir_local[q] = q == 2;
6814                         t->render_modellight_ambient[q] = 0;
6815                         t->render_modellight_diffuse[q] = 0;
6816                         t->render_modellight_specular[q] = 0;
6817                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6818                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6819                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6820                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6821                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6822                 }
6823         }
6824
6825         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6826         {
6827                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6828                 // attribute, we punt it to the lightmap path and hope for the best,
6829                 // but lighting doesn't work.
6830                 //
6831                 // FIXME: this is fine for effects but CSQC polygons should be subject
6832                 // to lighting.
6833                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6834                 for (q = 0; q < 3; q++)
6835                 {
6836                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6837                         t->render_modellight_lightdir_world[q] = q == 2;
6838                         t->render_modellight_lightdir_local[q] = q == 2;
6839                         t->render_modellight_ambient[q] = 0;
6840                         t->render_modellight_diffuse[q] = 0;
6841                         t->render_modellight_specular[q] = 0;
6842                         t->render_lightmap_ambient[q] = 0;
6843                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6844                         t->render_lightmap_specular[q] = 0;
6845                         t->render_rtlight_diffuse[q] = 0;
6846                         t->render_rtlight_specular[q] = 0;
6847                 }
6848         }
6849
6850         for (q = 0; q < 3; q++)
6851         {
6852                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6853                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6854         }
6855
6856         if (rsurface.ent_flags & RENDER_ADDITIVE)
6857                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6858         else if (t->currentalpha < 1)
6859                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6860         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6861         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6862                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6863         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6864                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6865         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6866                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6867         if (t->backgroundshaderpass)
6868                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6869         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6870         {
6871                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6872                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6873         }
6874         else
6875                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6876         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6877         {
6878                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6879                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6880         }
6881         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6882                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6883
6884         // there is no tcmod
6885         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6886         {
6887                 t->currenttexmatrix = r_waterscrollmatrix;
6888                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6889         }
6890         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6891         {
6892                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6893                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6894         }
6895
6896         if (t->materialshaderpass)
6897                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6898                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6899
6900         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6901         if (t->currentskinframe->qpixels)
6902                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6903         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6904         if (!t->basetexture)
6905                 t->basetexture = r_texture_notexture;
6906         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6907         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6908         t->nmaptexture = t->currentskinframe->nmap;
6909         if (!t->nmaptexture)
6910                 t->nmaptexture = r_texture_blanknormalmap;
6911         t->glosstexture = r_texture_black;
6912         t->glowtexture = t->currentskinframe->glow;
6913         t->fogtexture = t->currentskinframe->fog;
6914         t->reflectmasktexture = t->currentskinframe->reflect;
6915         if (t->backgroundshaderpass)
6916         {
6917                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6918                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6919                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6920                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6921                 t->backgroundglosstexture = r_texture_black;
6922                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6923                 if (!t->backgroundnmaptexture)
6924                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6925                 // make sure that if glow is going to be used, both textures are not NULL
6926                 if (!t->backgroundglowtexture && t->glowtexture)
6927                         t->backgroundglowtexture = r_texture_black;
6928                 if (!t->glowtexture && t->backgroundglowtexture)
6929                         t->glowtexture = r_texture_black;
6930         }
6931         else
6932         {
6933                 t->backgroundbasetexture = r_texture_white;
6934                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6935                 t->backgroundglosstexture = r_texture_black;
6936                 t->backgroundglowtexture = NULL;
6937         }
6938         t->specularpower = r_shadow_glossexponent.value;
6939         // TODO: store reference values for these in the texture?
6940         if (r_shadow_gloss.integer > 0)
6941         {
6942                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6943                 {
6944                         if (r_shadow_glossintensity.value > 0)
6945                         {
6946                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6947                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6948                                 specularscale = r_shadow_glossintensity.value;
6949                         }
6950                 }
6951                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6952                 {
6953                         t->glosstexture = r_texture_white;
6954                         t->backgroundglosstexture = r_texture_white;
6955                         specularscale = r_shadow_gloss2intensity.value;
6956                         t->specularpower = r_shadow_gloss2exponent.value;
6957                 }
6958         }
6959         specularscale *= t->specularscalemod;
6960         t->specularpower *= t->specularpowermod;
6961
6962         // lightmaps mode looks bad with dlights using actual texturing, so turn
6963         // off the colormap and glossmap, but leave the normalmap on as it still
6964         // accurately represents the shading involved
6965         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6966         {
6967                 t->basetexture = r_texture_grey128;
6968                 t->pantstexture = r_texture_black;
6969                 t->shirttexture = r_texture_black;
6970                 if (gl_lightmaps.integer < 2)
6971                         t->nmaptexture = r_texture_blanknormalmap;
6972                 t->glosstexture = r_texture_black;
6973                 t->glowtexture = NULL;
6974                 t->fogtexture = NULL;
6975                 t->reflectmasktexture = NULL;
6976                 t->backgroundbasetexture = NULL;
6977                 if (gl_lightmaps.integer < 2)
6978                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6979                 t->backgroundglosstexture = r_texture_black;
6980                 t->backgroundglowtexture = NULL;
6981                 specularscale = 0;
6982                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6983         }
6984
6985         if (specularscale != 1.0f)
6986         {
6987                 for (q = 0; q < 3; q++)
6988                 {
6989                         t->render_modellight_specular[q] *= specularscale;
6990                         t->render_lightmap_specular[q] *= specularscale;
6991                         t->render_rtlight_specular[q] *= specularscale;
6992                 }
6993         }
6994
6995         t->currentblendfunc[0] = GL_ONE;
6996         t->currentblendfunc[1] = GL_ZERO;
6997         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6998         {
6999                 t->currentblendfunc[0] = GL_SRC_ALPHA;
7000                 t->currentblendfunc[1] = GL_ONE;
7001         }
7002         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7003         {
7004                 t->currentblendfunc[0] = GL_SRC_ALPHA;
7005                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
7006         }
7007         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7008         {
7009                 t->currentblendfunc[0] = t->customblendfunc[0];
7010                 t->currentblendfunc[1] = t->customblendfunc[1];
7011         }
7012
7013         return t;
7014 }
7015
7016 rsurfacestate_t rsurface;
7017
7018 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7019 {
7020         dp_model_t *model = ent->model;
7021         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7022         //      return;
7023         rsurface.entity = (entity_render_t *)ent;
7024         rsurface.skeleton = ent->skeleton;
7025         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7026         rsurface.ent_skinnum = ent->skinnum;
7027         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;
7028         rsurface.ent_flags = ent->flags;
7029         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7030                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7031         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7032         rsurface.matrix = ent->matrix;
7033         rsurface.inversematrix = ent->inversematrix;
7034         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7035         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7036         R_EntityMatrix(&rsurface.matrix);
7037         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7038         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7039         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7040         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7041         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7042         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7043         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7044         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7045         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7046         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7047         if (ent->model->brush.submodel && !prepass)
7048         {
7049                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7050                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7051         }
7052         // if the animcache code decided it should use the shader path, skip the deform step
7053         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7054         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7055         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7056         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7057         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7058         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7059         {
7060                 if (ent->animcache_vertex3f)
7061                 {
7062                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7063                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7064                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7065                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7066                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7067                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7068                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7069                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7070                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7071                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7072                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7073                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7074                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7075                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7076                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7077                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7078                 }
7079                 else if (wanttangents)
7080                 {
7081                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7082                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7083                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7084                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7085                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7086                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7087                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7088                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7089                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7090                         rsurface.modelvertex3f_vertexbuffer = NULL;
7091                         rsurface.modelvertex3f_bufferoffset = 0;
7092                         rsurface.modelvertex3f_vertexbuffer = 0;
7093                         rsurface.modelvertex3f_bufferoffset = 0;
7094                         rsurface.modelsvector3f_vertexbuffer = 0;
7095                         rsurface.modelsvector3f_bufferoffset = 0;
7096                         rsurface.modeltvector3f_vertexbuffer = 0;
7097                         rsurface.modeltvector3f_bufferoffset = 0;
7098                         rsurface.modelnormal3f_vertexbuffer = 0;
7099                         rsurface.modelnormal3f_bufferoffset = 0;
7100                 }
7101                 else if (wantnormals)
7102                 {
7103                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7104                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7105                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7106                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7107                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7108                         rsurface.modelsvector3f = NULL;
7109                         rsurface.modeltvector3f = NULL;
7110                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7111                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7112                         rsurface.modelvertex3f_vertexbuffer = NULL;
7113                         rsurface.modelvertex3f_bufferoffset = 0;
7114                         rsurface.modelvertex3f_vertexbuffer = 0;
7115                         rsurface.modelvertex3f_bufferoffset = 0;
7116                         rsurface.modelsvector3f_vertexbuffer = 0;
7117                         rsurface.modelsvector3f_bufferoffset = 0;
7118                         rsurface.modeltvector3f_vertexbuffer = 0;
7119                         rsurface.modeltvector3f_bufferoffset = 0;
7120                         rsurface.modelnormal3f_vertexbuffer = 0;
7121                         rsurface.modelnormal3f_bufferoffset = 0;
7122                 }
7123                 else
7124                 {
7125                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7126                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7127                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7128                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7129                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7130                         rsurface.modelsvector3f = NULL;
7131                         rsurface.modeltvector3f = NULL;
7132                         rsurface.modelnormal3f = NULL;
7133                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7134                         rsurface.modelvertex3f_vertexbuffer = NULL;
7135                         rsurface.modelvertex3f_bufferoffset = 0;
7136                         rsurface.modelvertex3f_vertexbuffer = 0;
7137                         rsurface.modelvertex3f_bufferoffset = 0;
7138                         rsurface.modelsvector3f_vertexbuffer = 0;
7139                         rsurface.modelsvector3f_bufferoffset = 0;
7140                         rsurface.modeltvector3f_vertexbuffer = 0;
7141                         rsurface.modeltvector3f_bufferoffset = 0;
7142                         rsurface.modelnormal3f_vertexbuffer = 0;
7143                         rsurface.modelnormal3f_bufferoffset = 0;
7144                 }
7145                 rsurface.modelgeneratedvertex = true;
7146         }
7147         else
7148         {
7149                 if (rsurface.entityskeletaltransform3x4)
7150                 {
7151                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7152                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7153                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7154                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7155                 }
7156                 else
7157                 {
7158                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7159                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7160                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7161                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7162                 }
7163                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7164                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7165                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7166                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7167                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7168                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7169                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7170                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7171                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7172                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7173                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7174                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7175                 rsurface.modelgeneratedvertex = false;
7176         }
7177         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7178         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7179         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7180         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7181         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7182         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7183         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7184         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7185         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7186         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7187         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7188         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7189         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7190         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7191         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7192         rsurface.modelelement3i = model->surfmesh.data_element3i;
7193         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7194         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7195         rsurface.modelelement3s = model->surfmesh.data_element3s;
7196         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7197         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7198         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7199         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7200         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7201         rsurface.modelsurfaces = model->data_surfaces;
7202         rsurface.batchgeneratedvertex = false;
7203         rsurface.batchfirstvertex = 0;
7204         rsurface.batchnumvertices = 0;
7205         rsurface.batchfirsttriangle = 0;
7206         rsurface.batchnumtriangles = 0;
7207         rsurface.batchvertex3f  = NULL;
7208         rsurface.batchvertex3f_vertexbuffer = NULL;
7209         rsurface.batchvertex3f_bufferoffset = 0;
7210         rsurface.batchsvector3f = NULL;
7211         rsurface.batchsvector3f_vertexbuffer = NULL;
7212         rsurface.batchsvector3f_bufferoffset = 0;
7213         rsurface.batchtvector3f = NULL;
7214         rsurface.batchtvector3f_vertexbuffer = NULL;
7215         rsurface.batchtvector3f_bufferoffset = 0;
7216         rsurface.batchnormal3f  = NULL;
7217         rsurface.batchnormal3f_vertexbuffer = NULL;
7218         rsurface.batchnormal3f_bufferoffset = 0;
7219         rsurface.batchlightmapcolor4f = NULL;
7220         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7221         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7222         rsurface.batchtexcoordtexture2f = NULL;
7223         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7224         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7225         rsurface.batchtexcoordlightmap2f = NULL;
7226         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7227         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7228         rsurface.batchskeletalindex4ub = NULL;
7229         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7230         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7231         rsurface.batchskeletalweight4ub = NULL;
7232         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7233         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7234         rsurface.batchelement3i = NULL;
7235         rsurface.batchelement3i_indexbuffer = NULL;
7236         rsurface.batchelement3i_bufferoffset = 0;
7237         rsurface.batchelement3s = NULL;
7238         rsurface.batchelement3s_indexbuffer = NULL;
7239         rsurface.batchelement3s_bufferoffset = 0;
7240         rsurface.forcecurrenttextureupdate = false;
7241 }
7242
7243 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
7244 {
7245         rsurface.entity = r_refdef.scene.worldentity;
7246         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7247                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7248                 // A better approach could be making this copy only once per frame.
7249                 static entity_render_t custom_entity;
7250                 int q;
7251                 custom_entity = *rsurface.entity;
7252                 for (q = 0; q < 3; ++q) {
7253                         float colormod = q == 0 ? r : q == 1 ? g : b;
7254                         custom_entity.render_fullbright[q] *= colormod;
7255                         custom_entity.render_modellight_ambient[q] *= colormod;
7256                         custom_entity.render_modellight_diffuse[q] *= colormod;
7257                         custom_entity.render_lightmap_ambient[q] *= colormod;
7258                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7259                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7260                 }
7261                 custom_entity.alpha *= a;
7262                 rsurface.entity = &custom_entity;
7263         }
7264         rsurface.skeleton = NULL;
7265         rsurface.ent_skinnum = 0;
7266         rsurface.ent_qwskin = -1;
7267         rsurface.ent_flags = entflags;
7268         rsurface.shadertime = r_refdef.scene.time - shadertime;
7269         rsurface.modelnumvertices = numvertices;
7270         rsurface.modelnumtriangles = numtriangles;
7271         rsurface.matrix = *matrix;
7272         rsurface.inversematrix = *inversematrix;
7273         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7274         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7275         R_EntityMatrix(&rsurface.matrix);
7276         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7277         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7278         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7279         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7280         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7281         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7282         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7283         rsurface.frameblend[0].lerp = 1;
7284         rsurface.ent_alttextures = false;
7285         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7286         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7287         rsurface.entityskeletaltransform3x4 = NULL;
7288         rsurface.entityskeletaltransform3x4buffer = NULL;
7289         rsurface.entityskeletaltransform3x4offset = 0;
7290         rsurface.entityskeletaltransform3x4size = 0;
7291         rsurface.entityskeletalnumtransforms = 0;
7292         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7293         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7294         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7295         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7296         if (wanttangents)
7297         {
7298                 rsurface.modelvertex3f = (float *)vertex3f;
7299                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7300                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7301                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7302         }
7303         else if (wantnormals)
7304         {
7305                 rsurface.modelvertex3f = (float *)vertex3f;
7306                 rsurface.modelsvector3f = NULL;
7307                 rsurface.modeltvector3f = NULL;
7308                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7309         }
7310         else
7311         {
7312                 rsurface.modelvertex3f = (float *)vertex3f;
7313                 rsurface.modelsvector3f = NULL;
7314                 rsurface.modeltvector3f = NULL;
7315                 rsurface.modelnormal3f = NULL;
7316         }
7317         rsurface.modelvertex3f_vertexbuffer = 0;
7318         rsurface.modelvertex3f_bufferoffset = 0;
7319         rsurface.modelsvector3f_vertexbuffer = 0;
7320         rsurface.modelsvector3f_bufferoffset = 0;
7321         rsurface.modeltvector3f_vertexbuffer = 0;
7322         rsurface.modeltvector3f_bufferoffset = 0;
7323         rsurface.modelnormal3f_vertexbuffer = 0;
7324         rsurface.modelnormal3f_bufferoffset = 0;
7325         rsurface.modelgeneratedvertex = true;
7326         rsurface.modellightmapcolor4f  = (float *)color4f;
7327         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7328         rsurface.modellightmapcolor4f_bufferoffset = 0;
7329         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7330         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7331         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7332         rsurface.modeltexcoordlightmap2f  = NULL;
7333         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7334         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7335         rsurface.modelskeletalindex4ub = NULL;
7336         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7337         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7338         rsurface.modelskeletalweight4ub = NULL;
7339         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7340         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7341         rsurface.modelelement3i = (int *)element3i;
7342         rsurface.modelelement3i_indexbuffer = NULL;
7343         rsurface.modelelement3i_bufferoffset = 0;
7344         rsurface.modelelement3s = (unsigned short *)element3s;
7345         rsurface.modelelement3s_indexbuffer = NULL;
7346         rsurface.modelelement3s_bufferoffset = 0;
7347         rsurface.modellightmapoffsets = NULL;
7348         rsurface.modelsurfaces = NULL;
7349         rsurface.batchgeneratedvertex = false;
7350         rsurface.batchfirstvertex = 0;
7351         rsurface.batchnumvertices = 0;
7352         rsurface.batchfirsttriangle = 0;
7353         rsurface.batchnumtriangles = 0;
7354         rsurface.batchvertex3f  = NULL;
7355         rsurface.batchvertex3f_vertexbuffer = NULL;
7356         rsurface.batchvertex3f_bufferoffset = 0;
7357         rsurface.batchsvector3f = NULL;
7358         rsurface.batchsvector3f_vertexbuffer = NULL;
7359         rsurface.batchsvector3f_bufferoffset = 0;
7360         rsurface.batchtvector3f = NULL;
7361         rsurface.batchtvector3f_vertexbuffer = NULL;
7362         rsurface.batchtvector3f_bufferoffset = 0;
7363         rsurface.batchnormal3f  = NULL;
7364         rsurface.batchnormal3f_vertexbuffer = NULL;
7365         rsurface.batchnormal3f_bufferoffset = 0;
7366         rsurface.batchlightmapcolor4f = NULL;
7367         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7368         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7369         rsurface.batchtexcoordtexture2f = NULL;
7370         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7371         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7372         rsurface.batchtexcoordlightmap2f = NULL;
7373         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7374         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7375         rsurface.batchskeletalindex4ub = NULL;
7376         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7377         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7378         rsurface.batchskeletalweight4ub = NULL;
7379         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7380         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7381         rsurface.batchelement3i = NULL;
7382         rsurface.batchelement3i_indexbuffer = NULL;
7383         rsurface.batchelement3i_bufferoffset = 0;
7384         rsurface.batchelement3s = NULL;
7385         rsurface.batchelement3s_indexbuffer = NULL;
7386         rsurface.batchelement3s_bufferoffset = 0;
7387         rsurface.forcecurrenttextureupdate = true;
7388
7389         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7390         {
7391                 if ((wantnormals || wanttangents) && !normal3f)
7392                 {
7393                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7394                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7395                 }
7396                 if (wanttangents && !svector3f)
7397                 {
7398                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7399                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7400                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7401                 }
7402         }
7403 }
7404
7405 float RSurf_FogPoint(const float *v)
7406 {
7407         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7408         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7409         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7410         float FogHeightFade = r_refdef.fogheightfade;
7411         float fogfrac;
7412         unsigned int fogmasktableindex;
7413         if (r_refdef.fogplaneviewabove)
7414                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7415         else
7416                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7417         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7418         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7419 }
7420
7421 float RSurf_FogVertex(const float *v)
7422 {
7423         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7424         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7425         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7426         float FogHeightFade = rsurface.fogheightfade;
7427         float fogfrac;
7428         unsigned int fogmasktableindex;
7429         if (r_refdef.fogplaneviewabove)
7430                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7431         else
7432                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7433         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7434         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7435 }
7436
7437 void RSurf_UploadBuffersForBatch(void)
7438 {
7439         // 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)
7440         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7441         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7442                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7443         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7444                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7445         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7446                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7447         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7448                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7449         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7450                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7451         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7452                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7453         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7454                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7455         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7456                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7457         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7458                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7459
7460         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7461                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7462         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7463                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7464
7465         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7466         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7467         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7468         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7469         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7470         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7471         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7472         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7473         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7474         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7475 }
7476
7477 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7478 {
7479         int i;
7480         for (i = 0;i < numelements;i++)
7481                 outelement3i[i] = inelement3i[i] + adjust;
7482 }
7483
7484 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7485 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7486 {
7487         int deformindex;
7488         int firsttriangle;
7489         int numtriangles;
7490         int firstvertex;
7491         int endvertex;
7492         int numvertices;
7493         int surfacefirsttriangle;
7494         int surfacenumtriangles;
7495         int surfacefirstvertex;
7496         int surfaceendvertex;
7497         int surfacenumvertices;
7498         int batchnumsurfaces = texturenumsurfaces;
7499         int batchnumvertices;
7500         int batchnumtriangles;
7501         int i, j;
7502         qboolean gaps;
7503         qboolean dynamicvertex;
7504         float amplitude;
7505         float animpos;
7506         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7507         float waveparms[4];
7508         unsigned char *ub;
7509         q3shaderinfo_deform_t *deform;
7510         const msurface_t *surface, *firstsurface;
7511         if (!texturenumsurfaces)
7512                 return;
7513         // find vertex range of this surface batch
7514         gaps = false;
7515         firstsurface = texturesurfacelist[0];
7516         firsttriangle = firstsurface->num_firsttriangle;
7517         batchnumvertices = 0;
7518         batchnumtriangles = 0;
7519         firstvertex = endvertex = firstsurface->num_firstvertex;
7520         for (i = 0;i < texturenumsurfaces;i++)
7521         {
7522                 surface = texturesurfacelist[i];
7523                 if (surface != firstsurface + i)
7524                         gaps = true;
7525                 surfacefirstvertex = surface->num_firstvertex;
7526                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7527                 surfacenumvertices = surface->num_vertices;
7528                 surfacenumtriangles = surface->num_triangles;
7529                 if (firstvertex > surfacefirstvertex)
7530                         firstvertex = surfacefirstvertex;
7531                 if (endvertex < surfaceendvertex)
7532                         endvertex = surfaceendvertex;
7533                 batchnumvertices += surfacenumvertices;
7534                 batchnumtriangles += surfacenumtriangles;
7535         }
7536
7537         r_refdef.stats[r_stat_batch_batches]++;
7538         if (gaps)
7539                 r_refdef.stats[r_stat_batch_withgaps]++;
7540         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7541         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7542         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7543
7544         // we now know the vertex range used, and if there are any gaps in it
7545         rsurface.batchfirstvertex = firstvertex;
7546         rsurface.batchnumvertices = endvertex - firstvertex;
7547         rsurface.batchfirsttriangle = firsttriangle;
7548         rsurface.batchnumtriangles = batchnumtriangles;
7549
7550         // check if any dynamic vertex processing must occur
7551         dynamicvertex = false;
7552
7553         // we must use vertexbuffers for rendering, we can upload vertex buffers
7554         // easily enough but if the basevertex is non-zero it becomes more
7555         // difficult, so force dynamicvertex path in that case - it's suboptimal
7556         // but the most optimal case is to have the geometry sources provide their
7557         // own anyway.
7558         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7559                 dynamicvertex = true;
7560
7561         // a cvar to force the dynamic vertex path to be taken, for debugging
7562         if (r_batch_debugdynamicvertexpath.integer)
7563         {
7564                 if (!dynamicvertex)
7565                 {
7566                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7567                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7568                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7569                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7570                 }
7571                 dynamicvertex = true;
7572         }
7573
7574         // if there is a chance of animated vertex colors, it's a dynamic batch
7575         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7576         {
7577                 if (!dynamicvertex)
7578                 {
7579                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7580                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7581                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7582                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7583                 }
7584                 dynamicvertex = true;
7585         }
7586
7587         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7588         {
7589                 switch (deform->deform)
7590                 {
7591                 default:
7592                 case Q3DEFORM_PROJECTIONSHADOW:
7593                 case Q3DEFORM_TEXT0:
7594                 case Q3DEFORM_TEXT1:
7595                 case Q3DEFORM_TEXT2:
7596                 case Q3DEFORM_TEXT3:
7597                 case Q3DEFORM_TEXT4:
7598                 case Q3DEFORM_TEXT5:
7599                 case Q3DEFORM_TEXT6:
7600                 case Q3DEFORM_TEXT7:
7601                 case Q3DEFORM_NONE:
7602                         break;
7603                 case Q3DEFORM_AUTOSPRITE:
7604                         if (!dynamicvertex)
7605                         {
7606                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7607                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7608                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7609                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7610                         }
7611                         dynamicvertex = true;
7612                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7613                         break;
7614                 case Q3DEFORM_AUTOSPRITE2:
7615                         if (!dynamicvertex)
7616                         {
7617                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7618                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7619                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7620                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7621                         }
7622                         dynamicvertex = true;
7623                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7624                         break;
7625                 case Q3DEFORM_NORMAL:
7626                         if (!dynamicvertex)
7627                         {
7628                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7629                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7630                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7631                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7632                         }
7633                         dynamicvertex = true;
7634                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7635                         break;
7636                 case Q3DEFORM_WAVE:
7637                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7638                                 break; // if wavefunc is a nop, ignore this transform
7639                         if (!dynamicvertex)
7640                         {
7641                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7642                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7643                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7644                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7645                         }
7646                         dynamicvertex = true;
7647                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7648                         break;
7649                 case Q3DEFORM_BULGE:
7650                         if (!dynamicvertex)
7651                         {
7652                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7653                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7654                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7655                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7656                         }
7657                         dynamicvertex = true;
7658                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7659                         break;
7660                 case Q3DEFORM_MOVE:
7661                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7662                                 break; // if wavefunc is a nop, ignore this transform
7663                         if (!dynamicvertex)
7664                         {
7665                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7666                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7667                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7668                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7669                         }
7670                         dynamicvertex = true;
7671                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7672                         break;
7673                 }
7674         }
7675         if (rsurface.texture->materialshaderpass)
7676         {
7677                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7678                 {
7679                 default:
7680                 case Q3TCGEN_TEXTURE:
7681                         break;
7682                 case Q3TCGEN_LIGHTMAP:
7683                         if (!dynamicvertex)
7684                         {
7685                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7686                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7687                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7688                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7689                         }
7690                         dynamicvertex = true;
7691                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7692                         break;
7693                 case Q3TCGEN_VECTOR:
7694                         if (!dynamicvertex)
7695                         {
7696                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7697                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7698                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7699                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7700                         }
7701                         dynamicvertex = true;
7702                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7703                         break;
7704                 case Q3TCGEN_ENVIRONMENT:
7705                         if (!dynamicvertex)
7706                         {
7707                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7708                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7709                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7710                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7711                         }
7712                         dynamicvertex = true;
7713                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7714                         break;
7715                 }
7716                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7717                 {
7718                         if (!dynamicvertex)
7719                         {
7720                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7721                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7722                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7723                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7724                         }
7725                         dynamicvertex = true;
7726                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7727                 }
7728         }
7729
7730         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7731         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7732         // we ensure this by treating the vertex batch as dynamic...
7733         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7734         {
7735                 if (!dynamicvertex)
7736                 {
7737                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7738                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7739                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7740                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7741                 }
7742                 dynamicvertex = true;
7743         }
7744
7745         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7746         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7747                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7748
7749         rsurface.batchvertex3f = rsurface.modelvertex3f;
7750         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7751         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7752         rsurface.batchsvector3f = rsurface.modelsvector3f;
7753         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7754         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7755         rsurface.batchtvector3f = rsurface.modeltvector3f;
7756         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7757         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7758         rsurface.batchnormal3f = rsurface.modelnormal3f;
7759         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7760         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7761         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7762         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7763         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7764         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7765         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7766         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7767         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7768         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7769         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7770         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7771         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7772         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7773         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7774         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7775         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7776         rsurface.batchelement3i = rsurface.modelelement3i;
7777         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7778         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7779         rsurface.batchelement3s = rsurface.modelelement3s;
7780         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7781         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7782         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7783         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7784         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7785         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7786         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7787
7788         // if any dynamic vertex processing has to occur in software, we copy the
7789         // entire surface list together before processing to rebase the vertices
7790         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7791         //
7792         // if any gaps exist and we do not have a static vertex buffer, we have to
7793         // copy the surface list together to avoid wasting upload bandwidth on the
7794         // vertices in the gaps.
7795         //
7796         // if gaps exist and we have a static vertex buffer, we can choose whether
7797         // to combine the index buffer ranges into one dynamic index buffer or
7798         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7799         //
7800         // in many cases the batch is reduced to one draw call.
7801
7802         rsurface.batchmultidraw = false;
7803         rsurface.batchmultidrawnumsurfaces = 0;
7804         rsurface.batchmultidrawsurfacelist = NULL;
7805
7806         if (!dynamicvertex)
7807         {
7808                 // static vertex data, just set pointers...
7809                 rsurface.batchgeneratedvertex = false;
7810                 // if there are gaps, we want to build a combined index buffer,
7811                 // otherwise use the original static buffer with an appropriate offset
7812                 if (gaps)
7813                 {
7814                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7815                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7816                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7817                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7818                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7819                         {
7820                                 rsurface.batchmultidraw = true;
7821                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7822                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7823                                 return;
7824                         }
7825                         // build a new triangle elements array for this batch
7826                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7827                         rsurface.batchfirsttriangle = 0;
7828                         numtriangles = 0;
7829                         for (i = 0;i < texturenumsurfaces;i++)
7830                         {
7831                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7832                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7833                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7834                                 numtriangles += surfacenumtriangles;
7835                         }
7836                         rsurface.batchelement3i_indexbuffer = NULL;
7837                         rsurface.batchelement3i_bufferoffset = 0;
7838                         rsurface.batchelement3s = NULL;
7839                         rsurface.batchelement3s_indexbuffer = NULL;
7840                         rsurface.batchelement3s_bufferoffset = 0;
7841                         if (endvertex <= 65536)
7842                         {
7843                                 // make a 16bit (unsigned short) index array if possible
7844                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7845                                 for (i = 0;i < numtriangles*3;i++)
7846                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7847                         }
7848                 }
7849                 else
7850                 {
7851                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7852                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7853                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7854                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7855                 }
7856                 return;
7857         }
7858
7859         // something needs software processing, do it for real...
7860         // we only directly handle separate array data in this case and then
7861         // generate interleaved data if needed...
7862         rsurface.batchgeneratedvertex = true;
7863         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7864         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7865         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7866         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7867
7868         // now copy the vertex data into a combined array and make an index array
7869         // (this is what Quake3 does all the time)
7870         // we also apply any skeletal animation here that would have been done in
7871         // the vertex shader, because most of the dynamic vertex animation cases
7872         // need actual vertex positions and normals
7873         //if (dynamicvertex)
7874         {
7875                 rsurface.batchvertex3f = NULL;
7876                 rsurface.batchvertex3f_vertexbuffer = NULL;
7877                 rsurface.batchvertex3f_bufferoffset = 0;
7878                 rsurface.batchsvector3f = NULL;
7879                 rsurface.batchsvector3f_vertexbuffer = NULL;
7880                 rsurface.batchsvector3f_bufferoffset = 0;
7881                 rsurface.batchtvector3f = NULL;
7882                 rsurface.batchtvector3f_vertexbuffer = NULL;
7883                 rsurface.batchtvector3f_bufferoffset = 0;
7884                 rsurface.batchnormal3f = NULL;
7885                 rsurface.batchnormal3f_vertexbuffer = NULL;
7886                 rsurface.batchnormal3f_bufferoffset = 0;
7887                 rsurface.batchlightmapcolor4f = NULL;
7888                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7889                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7890                 rsurface.batchtexcoordtexture2f = NULL;
7891                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7892                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7893                 rsurface.batchtexcoordlightmap2f = NULL;
7894                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7895                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7896                 rsurface.batchskeletalindex4ub = NULL;
7897                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7898                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7899                 rsurface.batchskeletalweight4ub = NULL;
7900                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7901                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7902                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7903                 rsurface.batchelement3i_indexbuffer = NULL;
7904                 rsurface.batchelement3i_bufferoffset = 0;
7905                 rsurface.batchelement3s = NULL;
7906                 rsurface.batchelement3s_indexbuffer = NULL;
7907                 rsurface.batchelement3s_bufferoffset = 0;
7908                 rsurface.batchskeletaltransform3x4buffer = NULL;
7909                 rsurface.batchskeletaltransform3x4offset = 0;
7910                 rsurface.batchskeletaltransform3x4size = 0;
7911                 // we'll only be setting up certain arrays as needed
7912                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7913                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7914                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7915                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7916                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7917                 {
7918                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7919                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7920                 }
7921                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7922                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7923                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7924                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7925                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7926                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7927                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7928                 {
7929                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7930                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7931                 }
7932                 numvertices = 0;
7933                 numtriangles = 0;
7934                 for (i = 0;i < texturenumsurfaces;i++)
7935                 {
7936                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7937                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7938                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7939                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7940                         // copy only the data requested
7941                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7942                         {
7943                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7944                                 {
7945                                         if (rsurface.batchvertex3f)
7946                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7947                                         else
7948                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7949                                 }
7950                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7951                                 {
7952                                         if (rsurface.modelnormal3f)
7953                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7954                                         else
7955                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7956                                 }
7957                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7958                                 {
7959                                         if (rsurface.modelsvector3f)
7960                                         {
7961                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7962                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7963                                         }
7964                                         else
7965                                         {
7966                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7967                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7968                                         }
7969                                 }
7970                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7971                                 {
7972                                         if (rsurface.modellightmapcolor4f)
7973                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7974                                         else
7975                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7976                                 }
7977                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7978                                 {
7979                                         if (rsurface.modeltexcoordtexture2f)
7980                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7981                                         else
7982                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7983                                 }
7984                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7985                                 {
7986                                         if (rsurface.modeltexcoordlightmap2f)
7987                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7988                                         else
7989                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7990                                 }
7991                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7992                                 {
7993                                         if (rsurface.modelskeletalindex4ub)
7994                                         {
7995                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7996                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7997                                         }
7998                                         else
7999                                         {
8000                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8001                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8002                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8003                                                 for (j = 0;j < surfacenumvertices;j++)
8004                                                         ub[j*4] = 255;
8005                                         }
8006                                 }
8007                         }
8008                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8009                         numvertices += surfacenumvertices;
8010                         numtriangles += surfacenumtriangles;
8011                 }
8012
8013                 // generate a 16bit index array as well if possible
8014                 // (in general, dynamic batches fit)
8015                 if (numvertices <= 65536)
8016                 {
8017                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8018                         for (i = 0;i < numtriangles*3;i++)
8019                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8020                 }
8021
8022                 // since we've copied everything, the batch now starts at 0
8023                 rsurface.batchfirstvertex = 0;
8024                 rsurface.batchnumvertices = batchnumvertices;
8025                 rsurface.batchfirsttriangle = 0;
8026                 rsurface.batchnumtriangles = batchnumtriangles;
8027         }
8028
8029         // apply skeletal animation that would have been done in the vertex shader
8030         if (rsurface.batchskeletaltransform3x4)
8031         {
8032                 const unsigned char *si;
8033                 const unsigned char *sw;
8034                 const float *t[4];
8035                 const float *b = rsurface.batchskeletaltransform3x4;
8036                 float *vp, *vs, *vt, *vn;
8037                 float w[4];
8038                 float m[3][4], n[3][4];
8039                 float tp[3], ts[3], tt[3], tn[3];
8040                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8041                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8042                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8043                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8044                 si = rsurface.batchskeletalindex4ub;
8045                 sw = rsurface.batchskeletalweight4ub;
8046                 vp = rsurface.batchvertex3f;
8047                 vs = rsurface.batchsvector3f;
8048                 vt = rsurface.batchtvector3f;
8049                 vn = rsurface.batchnormal3f;
8050                 memset(m[0], 0, sizeof(m));
8051                 memset(n[0], 0, sizeof(n));
8052                 for (i = 0;i < batchnumvertices;i++)
8053                 {
8054                         t[0] = b + si[0]*12;
8055                         if (sw[0] == 255)
8056                         {
8057                                 // common case - only one matrix
8058                                 m[0][0] = t[0][ 0];
8059                                 m[0][1] = t[0][ 1];
8060                                 m[0][2] = t[0][ 2];
8061                                 m[0][3] = t[0][ 3];
8062                                 m[1][0] = t[0][ 4];
8063                                 m[1][1] = t[0][ 5];
8064                                 m[1][2] = t[0][ 6];
8065                                 m[1][3] = t[0][ 7];
8066                                 m[2][0] = t[0][ 8];
8067                                 m[2][1] = t[0][ 9];
8068                                 m[2][2] = t[0][10];
8069                                 m[2][3] = t[0][11];
8070                         }
8071                         else if (sw[2] + sw[3])
8072                         {
8073                                 // blend 4 matrices
8074                                 t[1] = b + si[1]*12;
8075                                 t[2] = b + si[2]*12;
8076                                 t[3] = b + si[3]*12;
8077                                 w[0] = sw[0] * (1.0f / 255.0f);
8078                                 w[1] = sw[1] * (1.0f / 255.0f);
8079                                 w[2] = sw[2] * (1.0f / 255.0f);
8080                                 w[3] = sw[3] * (1.0f / 255.0f);
8081                                 // blend the matrices
8082                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8083                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8084                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8085                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8086                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8087                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8088                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8089                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8090                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8091                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8092                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8093                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8094                         }
8095                         else
8096                         {
8097                                 // blend 2 matrices
8098                                 t[1] = b + si[1]*12;
8099                                 w[0] = sw[0] * (1.0f / 255.0f);
8100                                 w[1] = sw[1] * (1.0f / 255.0f);
8101                                 // blend the matrices
8102                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8103                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8104                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8105                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8106                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8107                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8108                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8109                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8110                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8111                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8112                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8113                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8114                         }
8115                         si += 4;
8116                         sw += 4;
8117                         // modify the vertex
8118                         VectorCopy(vp, tp);
8119                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8120                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8121                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8122                         vp += 3;
8123                         if (vn)
8124                         {
8125                                 // the normal transformation matrix is a set of cross products...
8126                                 CrossProduct(m[1], m[2], n[0]);
8127                                 CrossProduct(m[2], m[0], n[1]);
8128                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8129                                 VectorCopy(vn, tn);
8130                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8131                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8132                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8133                                 VectorNormalize(vn);
8134                                 vn += 3;
8135                                 if (vs)
8136                                 {
8137                                         VectorCopy(vs, ts);
8138                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8139                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8140                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8141                                         VectorNormalize(vs);
8142                                         vs += 3;
8143                                         VectorCopy(vt, tt);
8144                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8145                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8146                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8147                                         VectorNormalize(vt);
8148                                         vt += 3;
8149                                 }
8150                         }
8151                 }
8152                 rsurface.batchskeletaltransform3x4 = NULL;
8153                 rsurface.batchskeletalnumtransforms = 0;
8154         }
8155
8156         // q1bsp surfaces rendered in vertex color mode have to have colors
8157         // calculated based on lightstyles
8158         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8159         {
8160                 // generate color arrays for the surfaces in this list
8161                 int c[4];
8162                 int scale;
8163                 int size3;
8164                 const int *offsets;
8165                 const unsigned char *lm;
8166                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8167                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8168                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8169                 numvertices = 0;
8170                 for (i = 0;i < texturenumsurfaces;i++)
8171                 {
8172                         surface = texturesurfacelist[i];
8173                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8174                         surfacenumvertices = surface->num_vertices;
8175                         if (surface->lightmapinfo->samples)
8176                         {
8177                                 for (j = 0;j < surfacenumvertices;j++)
8178                                 {
8179                                         lm = surface->lightmapinfo->samples + offsets[j];
8180                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8181                                         VectorScale(lm, scale, c);
8182                                         if (surface->lightmapinfo->styles[1] != 255)
8183                                         {
8184                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8185                                                 lm += size3;
8186                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8187                                                 VectorMA(c, scale, lm, c);
8188                                                 if (surface->lightmapinfo->styles[2] != 255)
8189                                                 {
8190                                                         lm += size3;
8191                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8192                                                         VectorMA(c, scale, lm, c);
8193                                                         if (surface->lightmapinfo->styles[3] != 255)
8194                                                         {
8195                                                                 lm += size3;
8196                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8197                                                                 VectorMA(c, scale, lm, c);
8198                                                         }
8199                                                 }
8200                                         }
8201                                         c[0] >>= 7;
8202                                         c[1] >>= 7;
8203                                         c[2] >>= 7;
8204                                         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);
8205                                         numvertices++;
8206                                 }
8207                         }
8208                         else
8209                         {
8210                                 for (j = 0;j < surfacenumvertices;j++)
8211                                 {
8212                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8213                                         numvertices++;
8214                                 }
8215                         }
8216                 }
8217         }
8218
8219         // if vertices are deformed (sprite flares and things in maps, possibly
8220         // water waves, bulges and other deformations), modify the copied vertices
8221         // in place
8222         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8223         {
8224                 float scale;
8225                 switch (deform->deform)
8226                 {
8227                 default:
8228                 case Q3DEFORM_PROJECTIONSHADOW:
8229                 case Q3DEFORM_TEXT0:
8230                 case Q3DEFORM_TEXT1:
8231                 case Q3DEFORM_TEXT2:
8232                 case Q3DEFORM_TEXT3:
8233                 case Q3DEFORM_TEXT4:
8234                 case Q3DEFORM_TEXT5:
8235                 case Q3DEFORM_TEXT6:
8236                 case Q3DEFORM_TEXT7:
8237                 case Q3DEFORM_NONE:
8238                         break;
8239                 case Q3DEFORM_AUTOSPRITE:
8240                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8241                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8242                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8243                         VectorNormalize(newforward);
8244                         VectorNormalize(newright);
8245                         VectorNormalize(newup);
8246 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8247 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8248 //                      rsurface.batchvertex3f_bufferoffset = 0;
8249 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8250 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8251 //                      rsurface.batchsvector3f_bufferoffset = 0;
8252 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8253 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8254 //                      rsurface.batchtvector3f_bufferoffset = 0;
8255 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8256 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8257 //                      rsurface.batchnormal3f_bufferoffset = 0;
8258                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8259                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8260                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8261                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8262                                 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);
8263                         // a single autosprite surface can contain multiple sprites...
8264                         for (j = 0;j < batchnumvertices - 3;j += 4)
8265                         {
8266                                 VectorClear(center);
8267                                 for (i = 0;i < 4;i++)
8268                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8269                                 VectorScale(center, 0.25f, center);
8270                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8271                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8272                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8273                                 for (i = 0;i < 4;i++)
8274                                 {
8275                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8276                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8277                                 }
8278                         }
8279                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8280                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8281                         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);
8282                         break;
8283                 case Q3DEFORM_AUTOSPRITE2:
8284                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8285                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8286                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8287                         VectorNormalize(newforward);
8288                         VectorNormalize(newright);
8289                         VectorNormalize(newup);
8290 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8291 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8292 //                      rsurface.batchvertex3f_bufferoffset = 0;
8293                         {
8294                                 const float *v1, *v2;
8295                                 vec3_t start, end;
8296                                 float f, l;
8297                                 struct
8298                                 {
8299                                         float length2;
8300                                         const float *v1;
8301                                         const float *v2;
8302                                 }
8303                                 shortest[2];
8304                                 memset(shortest, 0, sizeof(shortest));
8305                                 // a single autosprite surface can contain multiple sprites...
8306                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8307                                 {
8308                                         VectorClear(center);
8309                                         for (i = 0;i < 4;i++)
8310                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8311                                         VectorScale(center, 0.25f, center);
8312                                         // find the two shortest edges, then use them to define the
8313                                         // axis vectors for rotating around the central axis
8314                                         for (i = 0;i < 6;i++)
8315                                         {
8316                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8317                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8318                                                 l = VectorDistance2(v1, v2);
8319                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8320                                                 if (v1[2] != v2[2])
8321                                                         l += (1.0f / 1024.0f);
8322                                                 if (shortest[0].length2 > l || i == 0)
8323                                                 {
8324                                                         shortest[1] = shortest[0];
8325                                                         shortest[0].length2 = l;
8326                                                         shortest[0].v1 = v1;
8327                                                         shortest[0].v2 = v2;
8328                                                 }
8329                                                 else if (shortest[1].length2 > l || i == 1)
8330                                                 {
8331                                                         shortest[1].length2 = l;
8332                                                         shortest[1].v1 = v1;
8333                                                         shortest[1].v2 = v2;
8334                                                 }
8335                                         }
8336                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8337                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8338                                         // this calculates the right vector from the shortest edge
8339                                         // and the up vector from the edge midpoints
8340                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8341                                         VectorNormalize(right);
8342                                         VectorSubtract(end, start, up);
8343                                         VectorNormalize(up);
8344                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8345                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8346                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8347                                         VectorNegate(forward, forward);
8348                                         VectorReflect(forward, 0, up, forward);
8349                                         VectorNormalize(forward);
8350                                         CrossProduct(up, forward, newright);
8351                                         VectorNormalize(newright);
8352                                         // rotate the quad around the up axis vector, this is made
8353                                         // especially easy by the fact we know the quad is flat,
8354                                         // so we only have to subtract the center position and
8355                                         // measure distance along the right vector, and then
8356                                         // multiply that by the newright vector and add back the
8357                                         // center position
8358                                         // we also need to subtract the old position to undo the
8359                                         // displacement from the center, which we do with a
8360                                         // DotProduct, the subtraction/addition of center is also
8361                                         // optimized into DotProducts here
8362                                         l = DotProduct(right, center);
8363                                         for (i = 0;i < 4;i++)
8364                                         {
8365                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8366                                                 f = DotProduct(right, v1) - l;
8367                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8368                                         }
8369                                 }
8370                         }
8371                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8372                         {
8373 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8374 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8375 //                              rsurface.batchnormal3f_bufferoffset = 0;
8376                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8377                         }
8378                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8379                         {
8380 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8381 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8382 //                              rsurface.batchsvector3f_bufferoffset = 0;
8383 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8384 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8385 //                              rsurface.batchtvector3f_bufferoffset = 0;
8386                                 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);
8387                         }
8388                         break;
8389                 case Q3DEFORM_NORMAL:
8390                         // deform the normals to make reflections wavey
8391                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8392                         rsurface.batchnormal3f_vertexbuffer = NULL;
8393                         rsurface.batchnormal3f_bufferoffset = 0;
8394                         for (j = 0;j < batchnumvertices;j++)
8395                         {
8396                                 float vertex[3];
8397                                 float *normal = rsurface.batchnormal3f + 3*j;
8398                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8399                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8400                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8401                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8402                                 VectorNormalize(normal);
8403                         }
8404                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8405                         {
8406 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8407 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8408 //                              rsurface.batchsvector3f_bufferoffset = 0;
8409 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8410 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8411 //                              rsurface.batchtvector3f_bufferoffset = 0;
8412                                 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);
8413                         }
8414                         break;
8415                 case Q3DEFORM_WAVE:
8416                         // deform vertex array to make wavey water and flags and such
8417                         waveparms[0] = deform->waveparms[0];
8418                         waveparms[1] = deform->waveparms[1];
8419                         waveparms[2] = deform->waveparms[2];
8420                         waveparms[3] = deform->waveparms[3];
8421                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8422                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8423                         // this is how a divisor of vertex influence on deformation
8424                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8425                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8426 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8427 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8428 //                      rsurface.batchvertex3f_bufferoffset = 0;
8429 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8430 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8431 //                      rsurface.batchnormal3f_bufferoffset = 0;
8432                         for (j = 0;j < batchnumvertices;j++)
8433                         {
8434                                 // if the wavefunc depends on time, evaluate it per-vertex
8435                                 if (waveparms[3])
8436                                 {
8437                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8438                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8439                                 }
8440                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8441                         }
8442                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8443                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8444                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8445                         {
8446 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8447 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8448 //                              rsurface.batchsvector3f_bufferoffset = 0;
8449 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8450 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8451 //                              rsurface.batchtvector3f_bufferoffset = 0;
8452                                 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);
8453                         }
8454                         break;
8455                 case Q3DEFORM_BULGE:
8456                         // deform vertex array to make the surface have moving bulges
8457 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8458 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8459 //                      rsurface.batchvertex3f_bufferoffset = 0;
8460 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8461 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8462 //                      rsurface.batchnormal3f_bufferoffset = 0;
8463                         for (j = 0;j < batchnumvertices;j++)
8464                         {
8465                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8466                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8467                         }
8468                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8469                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8470                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8471                         {
8472 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8473 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8474 //                              rsurface.batchsvector3f_bufferoffset = 0;
8475 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8476 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8477 //                              rsurface.batchtvector3f_bufferoffset = 0;
8478                                 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);
8479                         }
8480                         break;
8481                 case Q3DEFORM_MOVE:
8482                         // deform vertex array
8483                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8484                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8485                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8486                         VectorScale(deform->parms, scale, waveparms);
8487 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8488 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8489 //                      rsurface.batchvertex3f_bufferoffset = 0;
8490                         for (j = 0;j < batchnumvertices;j++)
8491                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8492                         break;
8493                 }
8494         }
8495
8496         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8497         {
8498         // generate texcoords based on the chosen texcoord source
8499                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8500                 {
8501                 default:
8502                 case Q3TCGEN_TEXTURE:
8503                         break;
8504                 case Q3TCGEN_LIGHTMAP:
8505         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8506         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8507         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8508                         if (rsurface.batchtexcoordlightmap2f)
8509                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8510                         break;
8511                 case Q3TCGEN_VECTOR:
8512         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8513         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8514         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8515                         for (j = 0;j < batchnumvertices;j++)
8516                         {
8517                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8518                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8519                         }
8520                         break;
8521                 case Q3TCGEN_ENVIRONMENT:
8522                         // make environment reflections using a spheremap
8523                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8524                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8525                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8526                         for (j = 0;j < batchnumvertices;j++)
8527                         {
8528                                 // identical to Q3A's method, but executed in worldspace so
8529                                 // carried models can be shiny too
8530
8531                                 float viewer[3], d, reflected[3], worldreflected[3];
8532
8533                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8534                                 // VectorNormalize(viewer);
8535
8536                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8537
8538                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8539                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8540                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8541                                 // note: this is proportinal to viewer, so we can normalize later
8542
8543                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8544                                 VectorNormalize(worldreflected);
8545
8546                                 // note: this sphere map only uses world x and z!
8547                                 // so positive and negative y will LOOK THE SAME.
8548                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8549                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8550                         }
8551                         break;
8552                 }
8553                 // the only tcmod that needs software vertex processing is turbulent, so
8554                 // check for it here and apply the changes if needed
8555                 // and we only support that as the first one
8556                 // (handling a mixture of turbulent and other tcmods would be problematic
8557                 //  without punting it entirely to a software path)
8558                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8559                 {
8560                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8561                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8562         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8563         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8564         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8565                         for (j = 0;j < batchnumvertices;j++)
8566                         {
8567                                 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);
8568                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8569                         }
8570                 }
8571         }
8572 }
8573
8574 void RSurf_DrawBatch(void)
8575 {
8576         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8577         // through the pipeline, killing it earlier in the pipeline would have
8578         // per-surface overhead rather than per-batch overhead, so it's best to
8579         // reject it here, before it hits glDraw.
8580         if (rsurface.batchnumtriangles == 0)
8581                 return;
8582 #if 0
8583         // batch debugging code
8584         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8585         {
8586                 int i;
8587                 int j;
8588                 int c;
8589                 const int *e;
8590                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8591                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8592                 {
8593                         c = e[i];
8594                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8595                         {
8596                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8597                                 {
8598                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8599                                                 Sys_Error("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name);
8600                                         break;
8601                                 }
8602                         }
8603                 }
8604         }
8605 #endif
8606         if (rsurface.batchmultidraw)
8607         {
8608                 // issue multiple draws rather than copying index data
8609                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8610                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8611                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8612                 for (i = 0;i < numsurfaces;)
8613                 {
8614                         // combine consecutive surfaces as one draw
8615                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8616                                 if (surfacelist[j] != surfacelist[k] + 1)
8617                                         break;
8618                         firstvertex = surfacelist[i]->num_firstvertex;
8619                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8620                         firsttriangle = surfacelist[i]->num_firsttriangle;
8621                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8622                         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);
8623                         i = j;
8624                 }
8625         }
8626         else
8627         {
8628                 // there is only one consecutive run of index data (may have been combined)
8629                 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);
8630         }
8631 }
8632
8633 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8634 {
8635         // pick the closest matching water plane
8636         int planeindex, vertexindex, bestplaneindex = -1;
8637         float d, bestd;
8638         vec3_t vert;
8639         const float *v;
8640         r_waterstate_waterplane_t *p;
8641         qboolean prepared = false;
8642         bestd = 0;
8643         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8644         {
8645                 if(p->camera_entity != rsurface.texture->camera_entity)
8646                         continue;
8647                 d = 0;
8648                 if(!prepared)
8649                 {
8650                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8651                         prepared = true;
8652                         if(rsurface.batchnumvertices == 0)
8653                                 break;
8654                 }
8655                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8656                 {
8657                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8658                         d += fabs(PlaneDiff(vert, &p->plane));
8659                 }
8660                 if (bestd > d || bestplaneindex < 0)
8661                 {
8662                         bestd = d;
8663                         bestplaneindex = planeindex;
8664                 }
8665         }
8666         return bestplaneindex;
8667         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8668         // this situation though, as it might be better to render single larger
8669         // batches with useless stuff (backface culled for example) than to
8670         // render multiple smaller batches
8671 }
8672
8673 void RSurf_SetupDepthAndCulling(void)
8674 {
8675         // submodels are biased to avoid z-fighting with world surfaces that they
8676         // may be exactly overlapping (avoids z-fighting artifacts on certain
8677         // doors and things in Quake maps)
8678         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8679         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8680         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8681         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8682 }
8683
8684 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8685 {
8686         int j;
8687         const float *v;
8688         float p[3], mins[3], maxs[3];
8689         int scissor[4];
8690         // transparent sky would be ridiculous
8691         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8692                 return;
8693         R_SetupShader_Generic_NoTexture(false, false);
8694         skyrenderlater = true;
8695         RSurf_SetupDepthAndCulling();
8696         GL_DepthMask(true);
8697
8698         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8699         if (r_sky_scissor.integer)
8700         {
8701                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8702                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8703                 {
8704                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8705                         if (j > 0)
8706                         {
8707                                 if (mins[0] > p[0]) mins[0] = p[0];
8708                                 if (mins[1] > p[1]) mins[1] = p[1];
8709                                 if (mins[2] > p[2]) mins[2] = p[2];
8710                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8711                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8712                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8713                         }
8714                         else
8715                         {
8716                                 VectorCopy(p, mins);
8717                                 VectorCopy(p, maxs);
8718                         }
8719                 }
8720                 if (!R_ScissorForBBox(mins, maxs, scissor))
8721                 {
8722                         if (skyscissor[2])
8723                         {
8724                                 if (skyscissor[0] > scissor[0])
8725                                 {
8726                                         skyscissor[2] += skyscissor[0] - scissor[0];
8727                                         skyscissor[0] = scissor[0];
8728                                 }
8729                                 if (skyscissor[1] > scissor[1])
8730                                 {
8731                                         skyscissor[3] += skyscissor[1] - scissor[1];
8732                                         skyscissor[1] = scissor[1];
8733                                 }
8734                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8735                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8736                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8737                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8738                         }
8739                         else
8740                                 Vector4Copy(scissor, skyscissor);
8741                 }
8742         }
8743
8744         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8745         // skymasking on them, and Quake3 never did sky masking (unlike
8746         // software Quake and software Quake2), so disable the sky masking
8747         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8748         // and skymasking also looks very bad when noclipping outside the
8749         // level, so don't use it then either.
8750         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)
8751         {
8752                 R_Mesh_ResetTextureState();
8753                 if (skyrendermasked)
8754                 {
8755                         R_SetupShader_DepthOrShadow(false, false, false);
8756                         // depth-only (masking)
8757                         GL_ColorMask(0, 0, 0, 0);
8758                         // just to make sure that braindead drivers don't draw
8759                         // anything despite that colormask...
8760                         GL_BlendFunc(GL_ZERO, GL_ONE);
8761                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8762                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8763                 }
8764                 else
8765                 {
8766                         R_SetupShader_Generic_NoTexture(false, false);
8767                         // fog sky
8768                         GL_BlendFunc(GL_ONE, GL_ZERO);
8769                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8770                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8771                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8772                 }
8773                 RSurf_DrawBatch();
8774                 if (skyrendermasked)
8775                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8776         }
8777         R_Mesh_ResetTextureState();
8778         GL_Color(1, 1, 1, 1);
8779 }
8780
8781 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8782 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8783 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8784 {
8785         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8786                 return;
8787         if (prepass)
8788         {
8789                 // render screenspace normalmap to texture
8790                 GL_DepthMask(true);
8791                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8792                 RSurf_DrawBatch();
8793                 return;
8794         }
8795
8796         // bind lightmap texture
8797
8798         // water/refraction/reflection/camera surfaces have to be handled specially
8799         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8800         {
8801                 int start, end, startplaneindex;
8802                 for (start = 0;start < texturenumsurfaces;start = end)
8803                 {
8804                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8805                         if(startplaneindex < 0)
8806                         {
8807                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8808                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8809                                 end = start + 1;
8810                                 continue;
8811                         }
8812                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8813                                 ;
8814                         // now that we have a batch using the same planeindex, render it
8815                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8816                         {
8817                                 // render water or distortion background
8818                                 GL_DepthMask(true);
8819                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8820                                 RSurf_DrawBatch();
8821                                 // blend surface on top
8822                                 GL_DepthMask(false);
8823                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8824                                 RSurf_DrawBatch();
8825                         }
8826                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8827                         {
8828                                 // render surface with reflection texture as input
8829                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8830                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8831                                 RSurf_DrawBatch();
8832                         }
8833                 }
8834                 return;
8835         }
8836
8837         // render surface batch normally
8838         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8839         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8840         RSurf_DrawBatch();
8841 }
8842
8843 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8844 {
8845         int vi;
8846         int j;
8847         int texturesurfaceindex;
8848         int k;
8849         const msurface_t *surface;
8850         float surfacecolor4f[4];
8851
8852 //      R_Mesh_ResetTextureState();
8853         R_SetupShader_Generic_NoTexture(false, false);
8854
8855         GL_BlendFunc(GL_ONE, GL_ZERO);
8856         GL_DepthMask(writedepth);
8857
8858         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8859         vi = 0;
8860         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8861         {
8862                 surface = texturesurfacelist[texturesurfaceindex];
8863                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8864                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8865                 for (j = 0;j < surface->num_vertices;j++)
8866                 {
8867                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8868                         vi++;
8869                 }
8870         }
8871         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8872         RSurf_DrawBatch();
8873 }
8874
8875 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8876 {
8877         CHECKGLERROR
8878         RSurf_SetupDepthAndCulling();
8879         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8880         {
8881                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8882                 return;
8883         }
8884         switch (vid.renderpath)
8885         {
8886         case RENDERPATH_GL32:
8887         case RENDERPATH_GLES2:
8888                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8889                 break;
8890         }
8891         CHECKGLERROR
8892 }
8893
8894 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8895 {
8896         int i, j;
8897         int texturenumsurfaces, endsurface;
8898         texture_t *texture;
8899         const msurface_t *surface;
8900         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8901
8902         RSurf_ActiveModelEntity(ent, true, true, false);
8903
8904         if (r_transparentdepthmasking.integer)
8905         {
8906                 qboolean setup = false;
8907                 for (i = 0;i < numsurfaces;i = j)
8908                 {
8909                         j = i + 1;
8910                         surface = rsurface.modelsurfaces + surfacelist[i];
8911                         texture = surface->texture;
8912                         rsurface.texture = R_GetCurrentTexture(texture);
8913                         rsurface.lightmaptexture = NULL;
8914                         rsurface.deluxemaptexture = NULL;
8915                         rsurface.uselightmaptexture = false;
8916                         // scan ahead until we find a different texture
8917                         endsurface = min(i + 1024, numsurfaces);
8918                         texturenumsurfaces = 0;
8919                         texturesurfacelist[texturenumsurfaces++] = surface;
8920                         for (;j < endsurface;j++)
8921                         {
8922                                 surface = rsurface.modelsurfaces + surfacelist[j];
8923                                 if (texture != surface->texture)
8924                                         break;
8925                                 texturesurfacelist[texturenumsurfaces++] = surface;
8926                         }
8927                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8928                                 continue;
8929                         // render the range of surfaces as depth
8930                         if (!setup)
8931                         {
8932                                 setup = true;
8933                                 GL_ColorMask(0,0,0,0);
8934                                 GL_Color(1,1,1,1);
8935                                 GL_DepthTest(true);
8936                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8937                                 GL_DepthMask(true);
8938 //                              R_Mesh_ResetTextureState();
8939                         }
8940                         RSurf_SetupDepthAndCulling();
8941                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8942                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8943                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8944                         RSurf_DrawBatch();
8945                 }
8946                 if (setup)
8947                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8948         }
8949
8950         for (i = 0;i < numsurfaces;i = j)
8951         {
8952                 j = i + 1;
8953                 surface = rsurface.modelsurfaces + surfacelist[i];
8954                 texture = surface->texture;
8955                 rsurface.texture = R_GetCurrentTexture(texture);
8956                 // scan ahead until we find a different texture
8957                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8958                 texturenumsurfaces = 0;
8959                 texturesurfacelist[texturenumsurfaces++] = surface;
8960                         rsurface.lightmaptexture = surface->lightmaptexture;
8961                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8962                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8963                         for (;j < endsurface;j++)
8964                         {
8965                                 surface = rsurface.modelsurfaces + surfacelist[j];
8966                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8967                                         break;
8968                                 texturesurfacelist[texturenumsurfaces++] = surface;
8969                         }
8970                 // render the range of surfaces
8971                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8972         }
8973         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8974 }
8975
8976 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8977 {
8978         // transparent surfaces get pushed off into the transparent queue
8979         int surfacelistindex;
8980         const msurface_t *surface;
8981         vec3_t tempcenter, center;
8982         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8983         {
8984                 surface = texturesurfacelist[surfacelistindex];
8985                 if (r_transparent_sortsurfacesbynearest.integer)
8986                 {
8987                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8988                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8989                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8990                 }
8991                 else
8992                 {
8993                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8994                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8995                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8996                 }
8997                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8998                 if (rsurface.entity->transparent_offset) // transparent offset
8999                 {
9000                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9001                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9002                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9003                 }
9004                 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);
9005         }
9006 }
9007
9008 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9009 {
9010         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9011                 return;
9012         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9013                 return;
9014         RSurf_SetupDepthAndCulling();
9015         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9016         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9017         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9018         RSurf_DrawBatch();
9019 }
9020
9021 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9022 {
9023         CHECKGLERROR
9024         if (ui)
9025                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9026         else if (depthonly)
9027                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9028         else if (prepass)
9029         {
9030                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9031                         return;
9032                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9033                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9034                 else
9035                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9036         }
9037         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9038                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9039         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9040                 return;
9041         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9042         {
9043                 // in the deferred case, transparent surfaces were queued during prepass
9044                 if (!r_shadow_usingdeferredprepass)
9045                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9046         }
9047         else
9048         {
9049                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9050                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9051         }
9052         CHECKGLERROR
9053 }
9054
9055 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9056 {
9057         int i, j;
9058         texture_t *texture;
9059         R_FrameData_SetMark();
9060         // break the surface list down into batches by texture and use of lightmapping
9061         for (i = 0;i < numsurfaces;i = j)
9062         {
9063                 j = i + 1;
9064                 // texture is the base texture pointer, rsurface.texture is the
9065                 // current frame/skin the texture is directing us to use (for example
9066                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9067                 // use skin 1 instead)
9068                 texture = surfacelist[i]->texture;
9069                 rsurface.texture = R_GetCurrentTexture(texture);
9070                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9071                 {
9072                         // if this texture is not the kind we want, skip ahead to the next one
9073                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9074                                 ;
9075                         continue;
9076                 }
9077                 if(depthonly || prepass)
9078                 {
9079                         rsurface.lightmaptexture = NULL;
9080                         rsurface.deluxemaptexture = NULL;
9081                         rsurface.uselightmaptexture = false;
9082                         // simply scan ahead until we find a different texture or lightmap state
9083                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9084                                 ;
9085                 }
9086                 else
9087                 {
9088                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9089                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9090                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9091                         // simply scan ahead until we find a different texture or lightmap state
9092                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9093                                 ;
9094                 }
9095                 // render the range of surfaces
9096                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9097         }
9098         R_FrameData_ReturnToMark();
9099 }
9100
9101 float locboxvertex3f[6*4*3] =
9102 {
9103         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9104         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9105         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9106         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9107         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9108         1,0,0, 0,0,0, 0,1,0, 1,1,0
9109 };
9110
9111 unsigned short locboxelements[6*2*3] =
9112 {
9113          0, 1, 2, 0, 2, 3,
9114          4, 5, 6, 4, 6, 7,
9115          8, 9,10, 8,10,11,
9116         12,13,14, 12,14,15,
9117         16,17,18, 16,18,19,
9118         20,21,22, 20,22,23
9119 };
9120
9121 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9122 {
9123         int i, j;
9124         cl_locnode_t *loc = (cl_locnode_t *)ent;
9125         vec3_t mins, size;
9126         float vertex3f[6*4*3];
9127         CHECKGLERROR
9128         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9129         GL_DepthMask(false);
9130         GL_DepthRange(0, 1);
9131         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9132         GL_DepthTest(true);
9133         GL_CullFace(GL_NONE);
9134         R_EntityMatrix(&identitymatrix);
9135
9136 //      R_Mesh_ResetTextureState();
9137
9138         i = surfacelist[0];
9139         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9140                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9141                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9142                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9143
9144         if (VectorCompare(loc->mins, loc->maxs))
9145         {
9146                 VectorSet(size, 2, 2, 2);
9147                 VectorMA(loc->mins, -0.5f, size, mins);
9148         }
9149         else
9150         {
9151                 VectorCopy(loc->mins, mins);
9152                 VectorSubtract(loc->maxs, loc->mins, size);
9153         }
9154
9155         for (i = 0;i < 6*4*3;)
9156                 for (j = 0;j < 3;j++, i++)
9157                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9158
9159         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9160         R_SetupShader_Generic_NoTexture(false, false);
9161         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9162 }
9163
9164 void R_DrawLocs(void)
9165 {
9166         int index;
9167         cl_locnode_t *loc, *nearestloc;
9168         vec3_t center;
9169         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9170         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9171         {
9172                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9173                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9174         }
9175 }
9176
9177 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9178 {
9179         if (decalsystem->decals)
9180                 Mem_Free(decalsystem->decals);
9181         memset(decalsystem, 0, sizeof(*decalsystem));
9182 }
9183
9184 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)
9185 {
9186         tridecal_t *decal;
9187         tridecal_t *decals;
9188         int i;
9189
9190         // expand or initialize the system
9191         if (decalsystem->maxdecals <= decalsystem->numdecals)
9192         {
9193                 decalsystem_t old = *decalsystem;
9194                 qboolean useshortelements;
9195                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9196                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9197                 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)));
9198                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9199                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9200                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9201                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9202                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9203                 if (decalsystem->numdecals)
9204                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9205                 if (old.decals)
9206                         Mem_Free(old.decals);
9207                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9208                         decalsystem->element3i[i] = i;
9209                 if (useshortelements)
9210                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9211                                 decalsystem->element3s[i] = i;
9212         }
9213
9214         // grab a decal and search for another free slot for the next one
9215         decals = decalsystem->decals;
9216         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9217         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9218                 ;
9219         decalsystem->freedecal = i;
9220         if (decalsystem->numdecals <= i)
9221                 decalsystem->numdecals = i + 1;
9222
9223         // initialize the decal
9224         decal->lived = 0;
9225         decal->triangleindex = triangleindex;
9226         decal->surfaceindex = surfaceindex;
9227         decal->decalsequence = decalsequence;
9228         decal->color4f[0][0] = c0[0];
9229         decal->color4f[0][1] = c0[1];
9230         decal->color4f[0][2] = c0[2];
9231         decal->color4f[0][3] = 1;
9232         decal->color4f[1][0] = c1[0];
9233         decal->color4f[1][1] = c1[1];
9234         decal->color4f[1][2] = c1[2];
9235         decal->color4f[1][3] = 1;
9236         decal->color4f[2][0] = c2[0];
9237         decal->color4f[2][1] = c2[1];
9238         decal->color4f[2][2] = c2[2];
9239         decal->color4f[2][3] = 1;
9240         decal->vertex3f[0][0] = v0[0];
9241         decal->vertex3f[0][1] = v0[1];
9242         decal->vertex3f[0][2] = v0[2];
9243         decal->vertex3f[1][0] = v1[0];
9244         decal->vertex3f[1][1] = v1[1];
9245         decal->vertex3f[1][2] = v1[2];
9246         decal->vertex3f[2][0] = v2[0];
9247         decal->vertex3f[2][1] = v2[1];
9248         decal->vertex3f[2][2] = v2[2];
9249         decal->texcoord2f[0][0] = t0[0];
9250         decal->texcoord2f[0][1] = t0[1];
9251         decal->texcoord2f[1][0] = t1[0];
9252         decal->texcoord2f[1][1] = t1[1];
9253         decal->texcoord2f[2][0] = t2[0];
9254         decal->texcoord2f[2][1] = t2[1];
9255         TriangleNormal(v0, v1, v2, decal->plane);
9256         VectorNormalize(decal->plane);
9257         decal->plane[3] = DotProduct(v0, decal->plane);
9258 }
9259
9260 extern cvar_t cl_decals_bias;
9261 extern cvar_t cl_decals_models;
9262 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9263 // baseparms, parms, temps
9264 static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9265 {
9266         int cornerindex;
9267         int index;
9268         float v[9][3];
9269         const float *vertex3f;
9270         const float *normal3f;
9271         int numpoints;
9272         float points[2][9][3];
9273         float temp[3];
9274         float tc[9][2];
9275         float f;
9276         float c[9][4];
9277         const int *e;
9278
9279         e = rsurface.modelelement3i + 3*triangleindex;
9280
9281         vertex3f = rsurface.modelvertex3f;
9282         normal3f = rsurface.modelnormal3f;
9283
9284         if (normal3f)
9285         {
9286                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9287                 {
9288                         index = 3*e[cornerindex];
9289                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9290                 }
9291         }
9292         else
9293         {
9294                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9295                 {
9296                         index = 3*e[cornerindex];
9297                         VectorCopy(vertex3f + index, v[cornerindex]);
9298                 }
9299         }
9300
9301         // cull backfaces
9302         //TriangleNormal(v[0], v[1], v[2], normal);
9303         //if (DotProduct(normal, localnormal) < 0.0f)
9304         //      continue;
9305         // clip by each of the box planes formed from the projection matrix
9306         // if anything survives, we emit the decal
9307         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]);
9308         if (numpoints < 3)
9309                 return;
9310         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]);
9311         if (numpoints < 3)
9312                 return;
9313         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]);
9314         if (numpoints < 3)
9315                 return;
9316         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]);
9317         if (numpoints < 3)
9318                 return;
9319         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]);
9320         if (numpoints < 3)
9321                 return;
9322         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]);
9323         if (numpoints < 3)
9324                 return;
9325         // some part of the triangle survived, so we have to accept it...
9326         if (dynamic)
9327         {
9328                 // dynamic always uses the original triangle
9329                 numpoints = 3;
9330                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9331                 {
9332                         index = 3*e[cornerindex];
9333                         VectorCopy(vertex3f + index, v[cornerindex]);
9334                 }
9335         }
9336         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9337         {
9338                 // convert vertex positions to texcoords
9339                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9340                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9341                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9342                 // calculate distance fade from the projection origin
9343                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9344                 f = bound(0.0f, f, 1.0f);
9345                 c[cornerindex][0] = r * f;
9346                 c[cornerindex][1] = g * f;
9347                 c[cornerindex][2] = b * f;
9348                 c[cornerindex][3] = 1.0f;
9349                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9350         }
9351         if (dynamic)
9352                 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);
9353         else
9354                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9355                         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);
9356 }
9357 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)
9358 {
9359         matrix4x4_t projection;
9360         decalsystem_t *decalsystem;
9361         qboolean dynamic;
9362         dp_model_t *model;
9363         const msurface_t *surface;
9364         const msurface_t *surfaces;
9365         const int *surfacelist;
9366         const texture_t *texture;
9367         int numtriangles;
9368         int numsurfacelist;
9369         int surfacelistindex;
9370         int surfaceindex;
9371         int triangleindex;
9372         float localorigin[3];
9373         float localnormal[3];
9374         float localmins[3];
9375         float localmaxs[3];
9376         float localsize;
9377         //float normal[3];
9378         float planes[6][4];
9379         float angles[3];
9380         bih_t *bih;
9381         int bih_triangles_count;
9382         int bih_triangles[256];
9383         int bih_surfaces[256];
9384
9385         decalsystem = &ent->decalsystem;
9386         model = ent->model;
9387         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9388         {
9389                 R_DecalSystem_Reset(&ent->decalsystem);
9390                 return;
9391         }
9392
9393         if (!model->brush.data_leafs && !cl_decals_models.integer)
9394         {
9395                 if (decalsystem->model)
9396                         R_DecalSystem_Reset(decalsystem);
9397                 return;
9398         }
9399
9400         if (decalsystem->model != model)
9401                 R_DecalSystem_Reset(decalsystem);
9402         decalsystem->model = model;
9403
9404         RSurf_ActiveModelEntity(ent, true, false, false);
9405
9406         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9407         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9408         VectorNormalize(localnormal);
9409         localsize = worldsize*rsurface.inversematrixscale;
9410         localmins[0] = localorigin[0] - localsize;
9411         localmins[1] = localorigin[1] - localsize;
9412         localmins[2] = localorigin[2] - localsize;
9413         localmaxs[0] = localorigin[0] + localsize;
9414         localmaxs[1] = localorigin[1] + localsize;
9415         localmaxs[2] = localorigin[2] + localsize;
9416
9417         //VectorCopy(localnormal, planes[4]);
9418         //VectorVectors(planes[4], planes[2], planes[0]);
9419         AnglesFromVectors(angles, localnormal, NULL, false);
9420         AngleVectors(angles, planes[0], planes[2], planes[4]);
9421         VectorNegate(planes[0], planes[1]);
9422         VectorNegate(planes[2], planes[3]);
9423         VectorNegate(planes[4], planes[5]);
9424         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9425         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9426         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9427         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9428         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9429         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9430
9431 #if 1
9432 // works
9433 {
9434         matrix4x4_t forwardprojection;
9435         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9436         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9437 }
9438 #else
9439 // broken
9440 {
9441         float projectionvector[4][3];
9442         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9443         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9444         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9445         projectionvector[0][0] = planes[0][0] * ilocalsize;
9446         projectionvector[0][1] = planes[1][0] * ilocalsize;
9447         projectionvector[0][2] = planes[2][0] * ilocalsize;
9448         projectionvector[1][0] = planes[0][1] * ilocalsize;
9449         projectionvector[1][1] = planes[1][1] * ilocalsize;
9450         projectionvector[1][2] = planes[2][1] * ilocalsize;
9451         projectionvector[2][0] = planes[0][2] * ilocalsize;
9452         projectionvector[2][1] = planes[1][2] * ilocalsize;
9453         projectionvector[2][2] = planes[2][2] * ilocalsize;
9454         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9455         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9456         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9457         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9458 }
9459 #endif
9460
9461         dynamic = model->surfmesh.isanimated;
9462         numsurfacelist = model->nummodelsurfaces;
9463         surfacelist = model->sortedmodelsurfaces;
9464         surfaces = model->data_surfaces;
9465
9466         bih = NULL;
9467         bih_triangles_count = -1;
9468         if(!dynamic)
9469         {
9470                 if(model->render_bih.numleafs)
9471                         bih = &model->render_bih;
9472                 else if(model->collision_bih.numleafs)
9473                         bih = &model->collision_bih;
9474         }
9475         if(bih)
9476                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9477         if(bih_triangles_count == 0)
9478                 return;
9479         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9480                 return;
9481         if(bih_triangles_count > 0)
9482         {
9483                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9484                 {
9485                         surfaceindex = bih_surfaces[triangleindex];
9486                         surface = surfaces + surfaceindex;
9487                         texture = surface->texture;
9488                         if (!texture)
9489                                 continue;
9490                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9491                                 continue;
9492                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9493                                 continue;
9494                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9495                 }
9496         }
9497         else
9498         {
9499                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9500                 {
9501                         surfaceindex = surfacelist[surfacelistindex];
9502                         surface = surfaces + surfaceindex;
9503                         // check cull box first because it rejects more than any other check
9504                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9505                                 continue;
9506                         // skip transparent surfaces
9507                         texture = surface->texture;
9508                         if (!texture)
9509                                 continue;
9510                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9511                                 continue;
9512                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9513                                 continue;
9514                         numtriangles = surface->num_triangles;
9515                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9516                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9517                 }
9518         }
9519 }
9520
9521 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9522 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)
9523 {
9524         int renderentityindex;
9525         float worldmins[3];
9526         float worldmaxs[3];
9527         entity_render_t *ent;
9528
9529         worldmins[0] = worldorigin[0] - worldsize;
9530         worldmins[1] = worldorigin[1] - worldsize;
9531         worldmins[2] = worldorigin[2] - worldsize;
9532         worldmaxs[0] = worldorigin[0] + worldsize;
9533         worldmaxs[1] = worldorigin[1] + worldsize;
9534         worldmaxs[2] = worldorigin[2] + worldsize;
9535
9536         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9537
9538         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9539         {
9540                 ent = r_refdef.scene.entities[renderentityindex];
9541                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9542                         continue;
9543
9544                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9545         }
9546 }
9547
9548 typedef struct r_decalsystem_splatqueue_s
9549 {
9550         vec3_t worldorigin;
9551         vec3_t worldnormal;
9552         float color[4];
9553         float tcrange[4];
9554         float worldsize;
9555         unsigned int decalsequence;
9556 }
9557 r_decalsystem_splatqueue_t;
9558
9559 int r_decalsystem_numqueued = 0;
9560 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9561
9562 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)
9563 {
9564         r_decalsystem_splatqueue_t *queue;
9565
9566         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9567                 return;
9568
9569         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9570         VectorCopy(worldorigin, queue->worldorigin);
9571         VectorCopy(worldnormal, queue->worldnormal);
9572         Vector4Set(queue->color, r, g, b, a);
9573         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9574         queue->worldsize = worldsize;
9575         queue->decalsequence = cl.decalsequence++;
9576 }
9577
9578 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9579 {
9580         int i;
9581         r_decalsystem_splatqueue_t *queue;
9582
9583         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9584                 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);
9585         r_decalsystem_numqueued = 0;
9586 }
9587
9588 extern cvar_t cl_decals_max;
9589 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9590 {
9591         int i;
9592         decalsystem_t *decalsystem = &ent->decalsystem;
9593         int numdecals;
9594         unsigned int killsequence;
9595         tridecal_t *decal;
9596         float frametime;
9597         float lifetime;
9598
9599         if (!decalsystem->numdecals)
9600                 return;
9601
9602         if (r_showsurfaces.integer)
9603                 return;
9604
9605         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9606         {
9607                 R_DecalSystem_Reset(decalsystem);
9608                 return;
9609         }
9610
9611         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9612         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9613
9614         if (decalsystem->lastupdatetime)
9615                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9616         else
9617                 frametime = 0;
9618         decalsystem->lastupdatetime = r_refdef.scene.time;
9619         numdecals = decalsystem->numdecals;
9620
9621         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9622         {
9623                 if (decal->color4f[0][3])
9624                 {
9625                         decal->lived += frametime;
9626                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9627                         {
9628                                 memset(decal, 0, sizeof(*decal));
9629                                 if (decalsystem->freedecal > i)
9630                                         decalsystem->freedecal = i;
9631                         }
9632                 }
9633         }
9634         decal = decalsystem->decals;
9635         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9636                 numdecals--;
9637
9638         // collapse the array by shuffling the tail decals into the gaps
9639         for (;;)
9640         {
9641                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9642                         decalsystem->freedecal++;
9643                 if (decalsystem->freedecal == numdecals)
9644                         break;
9645                 decal[decalsystem->freedecal] = decal[--numdecals];
9646         }
9647
9648         decalsystem->numdecals = numdecals;
9649
9650         if (numdecals <= 0)
9651         {
9652                 // if there are no decals left, reset decalsystem
9653                 R_DecalSystem_Reset(decalsystem);
9654         }
9655 }
9656
9657 extern skinframe_t *decalskinframe;
9658 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9659 {
9660         int i;
9661         decalsystem_t *decalsystem = &ent->decalsystem;
9662         int numdecals;
9663         tridecal_t *decal;
9664         float faderate;
9665         float alpha;
9666         float *v3f;
9667         float *c4f;
9668         float *t2f;
9669         const int *e;
9670         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9671         int numtris = 0;
9672
9673         numdecals = decalsystem->numdecals;
9674         if (!numdecals)
9675                 return;
9676
9677         if (r_showsurfaces.integer)
9678                 return;
9679
9680         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9681         {
9682                 R_DecalSystem_Reset(decalsystem);
9683                 return;
9684         }
9685
9686         // if the model is static it doesn't matter what value we give for
9687         // wantnormals and wanttangents, so this logic uses only rules applicable
9688         // to a model, knowing that they are meaningless otherwise
9689         RSurf_ActiveModelEntity(ent, false, false, false);
9690
9691         decalsystem->lastupdatetime = r_refdef.scene.time;
9692
9693         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9694
9695         // update vertex positions for animated models
9696         v3f = decalsystem->vertex3f;
9697         c4f = decalsystem->color4f;
9698         t2f = decalsystem->texcoord2f;
9699         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9700         {
9701                 if (!decal->color4f[0][3])
9702                         continue;
9703
9704                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9705                         continue;
9706
9707                 // skip backfaces
9708                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9709                         continue;
9710
9711                 // update color values for fading decals
9712                 if (decal->lived >= cl_decals_time.value)
9713                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9714                 else
9715                         alpha = 1.0f;
9716
9717                 c4f[ 0] = decal->color4f[0][0] * alpha;
9718                 c4f[ 1] = decal->color4f[0][1] * alpha;
9719                 c4f[ 2] = decal->color4f[0][2] * alpha;
9720                 c4f[ 3] = 1;
9721                 c4f[ 4] = decal->color4f[1][0] * alpha;
9722                 c4f[ 5] = decal->color4f[1][1] * alpha;
9723                 c4f[ 6] = decal->color4f[1][2] * alpha;
9724                 c4f[ 7] = 1;
9725                 c4f[ 8] = decal->color4f[2][0] * alpha;
9726                 c4f[ 9] = decal->color4f[2][1] * alpha;
9727                 c4f[10] = decal->color4f[2][2] * alpha;
9728                 c4f[11] = 1;
9729
9730                 t2f[0] = decal->texcoord2f[0][0];
9731                 t2f[1] = decal->texcoord2f[0][1];
9732                 t2f[2] = decal->texcoord2f[1][0];
9733                 t2f[3] = decal->texcoord2f[1][1];
9734                 t2f[4] = decal->texcoord2f[2][0];
9735                 t2f[5] = decal->texcoord2f[2][1];
9736
9737                 // update vertex positions for animated models
9738                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9739                 {
9740                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9741                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9742                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9743                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9744                 }
9745                 else
9746                 {
9747                         VectorCopy(decal->vertex3f[0], v3f);
9748                         VectorCopy(decal->vertex3f[1], v3f + 3);
9749                         VectorCopy(decal->vertex3f[2], v3f + 6);
9750                 }
9751
9752                 if (r_refdef.fogenabled)
9753                 {
9754                         alpha = RSurf_FogVertex(v3f);
9755                         VectorScale(c4f, alpha, c4f);
9756                         alpha = RSurf_FogVertex(v3f + 3);
9757                         VectorScale(c4f + 4, alpha, c4f + 4);
9758                         alpha = RSurf_FogVertex(v3f + 6);
9759                         VectorScale(c4f + 8, alpha, c4f + 8);
9760                 }
9761
9762                 v3f += 9;
9763                 c4f += 12;
9764                 t2f += 6;
9765                 numtris++;
9766         }
9767
9768         if (numtris > 0)
9769         {
9770                 r_refdef.stats[r_stat_drawndecals] += numtris;
9771
9772                 // now render the decals all at once
9773                 // (this assumes they all use one particle font texture!)
9774                 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);
9775 //              R_Mesh_ResetTextureState();
9776                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9777                 GL_DepthMask(false);
9778                 GL_DepthRange(0, 1);
9779                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9780                 GL_DepthTest(true);
9781                 GL_CullFace(GL_NONE);
9782                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9783                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9784                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9785         }
9786 }
9787
9788 static void R_DrawModelDecals(void)
9789 {
9790         int i, numdecals;
9791
9792         // fade faster when there are too many decals
9793         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9794         for (i = 0;i < r_refdef.scene.numentities;i++)
9795                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9796
9797         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9798         for (i = 0;i < r_refdef.scene.numentities;i++)
9799                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9800                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9801
9802         R_DecalSystem_ApplySplatEntitiesQueue();
9803
9804         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9805         for (i = 0;i < r_refdef.scene.numentities;i++)
9806                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9807
9808         r_refdef.stats[r_stat_totaldecals] += numdecals;
9809
9810         if (r_showsurfaces.integer || !r_drawdecals.integer)
9811                 return;
9812
9813         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9814
9815         for (i = 0;i < r_refdef.scene.numentities;i++)
9816         {
9817                 if (!r_refdef.viewcache.entityvisible[i])
9818                         continue;
9819                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9820                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9821         }
9822 }
9823
9824 static void R_DrawDebugModel(void)
9825 {
9826         entity_render_t *ent = rsurface.entity;
9827         int i, j, flagsmask;
9828         const msurface_t *surface;
9829         dp_model_t *model = ent->model;
9830
9831         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9832                 return;
9833
9834         if (r_showoverdraw.value > 0)
9835         {
9836                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9837                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9838                 R_SetupShader_Generic_NoTexture(false, false);
9839                 GL_DepthTest(false);
9840                 GL_DepthMask(false);
9841                 GL_DepthRange(0, 1);
9842                 GL_BlendFunc(GL_ONE, GL_ONE);
9843                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9844                 {
9845                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9846                                 continue;
9847                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9848                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9849                         {
9850                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9851                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9852                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9853                                         GL_Color(c, 0, 0, 1.0f);
9854                                 else if (ent == r_refdef.scene.worldentity)
9855                                         GL_Color(c, c, c, 1.0f);
9856                                 else
9857                                         GL_Color(0, c, 0, 1.0f);
9858                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9859                                 RSurf_DrawBatch();
9860                         }
9861                 }
9862                 rsurface.texture = NULL;
9863         }
9864
9865         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9866
9867 //      R_Mesh_ResetTextureState();
9868         R_SetupShader_Generic_NoTexture(false, false);
9869         GL_DepthRange(0, 1);
9870         GL_DepthTest(!r_showdisabledepthtest.integer);
9871         GL_DepthMask(false);
9872         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9873
9874         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9875         {
9876                 int triangleindex;
9877                 int bihleafindex;
9878                 qboolean cullbox = false;
9879                 const q3mbrush_t *brush;
9880                 const bih_t *bih = &model->collision_bih;
9881                 const bih_leaf_t *bihleaf;
9882                 float vertex3f[3][3];
9883                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9884                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9885                 {
9886                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9887                                 continue;
9888                         switch (bihleaf->type)
9889                         {
9890                         case BIH_BRUSH:
9891                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9892                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9893                                 {
9894                                         GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
9895                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9896                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9897                                 }
9898                                 break;
9899                         case BIH_COLLISIONTRIANGLE:
9900                                 triangleindex = bihleaf->itemindex;
9901                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9902                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9903                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9904                                 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);
9905                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9906                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9907                                 break;
9908                         case BIH_RENDERTRIANGLE:
9909                                 triangleindex = bihleaf->itemindex;
9910                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9911                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9912                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9913                                 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);
9914                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9915                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9916                                 break;
9917                         }
9918                 }
9919         }
9920
9921         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9922
9923 #ifndef USE_GLES2
9924         if (r_showtris.value > 0 && qglPolygonMode)
9925         {
9926                 if (r_showdisabledepthtest.integer)
9927                 {
9928                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9929                         GL_DepthMask(false);
9930                 }
9931                 else
9932                 {
9933                         GL_BlendFunc(GL_ONE, GL_ZERO);
9934                         GL_DepthMask(true);
9935                 }
9936                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9937                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9938                 {
9939                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9940                                 continue;
9941                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9942                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9943                         {
9944                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9945                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9946                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9947                                 else if (ent == r_refdef.scene.worldentity)
9948                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9949                                 else
9950                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9951                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9952                                 RSurf_DrawBatch();
9953                         }
9954                 }
9955                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9956                 rsurface.texture = NULL;
9957         }
9958
9959 # if 0
9960         // FIXME!  implement r_shownormals with just triangles
9961         if (r_shownormals.value != 0 && qglBegin)
9962         {
9963                 int l, k;
9964                 vec3_t v;
9965                 if (r_showdisabledepthtest.integer)
9966                 {
9967                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9968                         GL_DepthMask(false);
9969                 }
9970                 else
9971                 {
9972                         GL_BlendFunc(GL_ONE, GL_ZERO);
9973                         GL_DepthMask(true);
9974                 }
9975                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9976                 {
9977                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9978                                 continue;
9979                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9980                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9981                         {
9982                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9983                                 qglBegin(GL_LINES);
9984                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9985                                 {
9986                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9987                                         {
9988                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9989                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9990                                                 qglVertex3f(v[0], v[1], v[2]);
9991                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9992                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9993                                                 qglVertex3f(v[0], v[1], v[2]);
9994                                         }
9995                                 }
9996                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9997                                 {
9998                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9999                                         {
10000                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10001                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10002                                                 qglVertex3f(v[0], v[1], v[2]);
10003                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10004                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10005                                                 qglVertex3f(v[0], v[1], v[2]);
10006                                         }
10007                                 }
10008                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10009                                 {
10010                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10011                                         {
10012                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10013                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10014                                                 qglVertex3f(v[0], v[1], v[2]);
10015                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10016                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10017                                                 qglVertex3f(v[0], v[1], v[2]);
10018                                         }
10019                                 }
10020                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10021                                 {
10022                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10023                                         {
10024                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10025                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10026                                                 qglVertex3f(v[0], v[1], v[2]);
10027                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10028                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10029                                                 qglVertex3f(v[0], v[1], v[2]);
10030                                         }
10031                                 }
10032                                 qglEnd();
10033                                 CHECKGLERROR
10034                         }
10035                 }
10036                 rsurface.texture = NULL;
10037         }
10038 # endif
10039 #endif
10040 }
10041
10042 int r_maxsurfacelist = 0;
10043 const msurface_t **r_surfacelist = NULL;
10044 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10045 {
10046         int i, j, endj, flagsmask;
10047         dp_model_t *model = ent->model;
10048         msurface_t *surfaces;
10049         unsigned char *update;
10050         int numsurfacelist = 0;
10051         if (model == NULL)
10052                 return;
10053
10054         if (r_maxsurfacelist < model->num_surfaces)
10055         {
10056                 r_maxsurfacelist = model->num_surfaces;
10057                 if (r_surfacelist)
10058                         Mem_Free((msurface_t **)r_surfacelist);
10059                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10060         }
10061
10062         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10063                 RSurf_ActiveModelEntity(ent, false, false, false);
10064         else if (prepass)
10065                 RSurf_ActiveModelEntity(ent, true, true, true);
10066         else if (depthonly)
10067                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10068         else
10069                 RSurf_ActiveModelEntity(ent, true, true, false);
10070
10071         surfaces = model->data_surfaces;
10072         update = model->brushq1.lightmapupdateflags;
10073
10074         // update light styles
10075         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10076         {
10077                 model_brush_lightstyleinfo_t *style;
10078                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10079                 {
10080                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10081                         {
10082                                 int *list = style->surfacelist;
10083                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10084                                 for (j = 0;j < style->numsurfaces;j++)
10085                                         update[list[j]] = true;
10086                         }
10087                 }
10088         }
10089
10090         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10091
10092         if (debug)
10093         {
10094                 R_DrawDebugModel();
10095                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10096                 return;
10097         }
10098
10099         rsurface.lightmaptexture = NULL;
10100         rsurface.deluxemaptexture = NULL;
10101         rsurface.uselightmaptexture = false;
10102         rsurface.texture = NULL;
10103         rsurface.rtlight = NULL;
10104         numsurfacelist = 0;
10105         // add visible surfaces to draw list
10106         if (ent == r_refdef.scene.worldentity)
10107         {
10108                 // for the world entity, check surfacevisible
10109                 for (i = 0;i < model->nummodelsurfaces;i++)
10110                 {
10111                         j = model->sortedmodelsurfaces[i];
10112                         if (r_refdef.viewcache.world_surfacevisible[j])
10113                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10114                 }
10115         }
10116         else if (ui)
10117         {
10118                 // for ui we have to preserve the order of surfaces
10119                 for (i = 0; i < model->nummodelsurfaces; i++)
10120                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10121         }
10122         else
10123         {
10124                 // add all surfaces
10125                 for (i = 0; i < model->nummodelsurfaces; i++)
10126                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10127         }
10128         // don't do anything if there were no surfaces
10129         if (!numsurfacelist)
10130         {
10131                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10132                 return;
10133         }
10134         // update lightmaps if needed
10135         if (update)
10136         {
10137                 int updated = 0;
10138                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10139                 {
10140                         if (update[j])
10141                         {
10142                                 updated++;
10143                                 R_BuildLightMap(ent, surfaces + j);
10144                         }
10145                 }
10146         }
10147
10148         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10149
10150         // add to stats if desired
10151         if (r_speeds.integer && !skysurfaces && !depthonly)
10152         {
10153                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10154                 for (j = 0;j < numsurfacelist;j++)
10155                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10156         }
10157
10158         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10159 }
10160
10161 void R_DebugLine(vec3_t start, vec3_t end)
10162 {
10163         dp_model_t *mod = CL_Mesh_UI();
10164         msurface_t *surf;
10165         int e0, e1, e2, e3;
10166         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10167         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10168         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10169         vec4_t w[2], s[2];
10170
10171         // transform to screen coords first
10172         Vector4Set(w[0], start[0], start[1], start[2], 1);
10173         Vector4Set(w[1], end[0], end[1], end[2], 1);
10174         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10175         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10176         x1 = s[0][0] * vid_conwidth.value / vid.width;
10177         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10178         x2 = s[1][0] * vid_conwidth.value / vid.width;
10179         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10180         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10181
10182         // add the line to the UI mesh for drawing later
10183
10184         // width is measured in real pixels
10185         if (fabs(x2 - x1) > fabs(y2 - y1))
10186         {
10187                 offsetx = 0;
10188                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10189         }
10190         else
10191         {
10192                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10193                 offsety = 0;
10194         }
10195         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);
10196         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10197         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10198         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10199         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10200         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10201         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10202
10203 }
10204
10205
10206 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10207 {
10208         static texture_t texture;
10209
10210         // fake enough texture and surface state to render this geometry
10211
10212         texture.update_lastrenderframe = -1; // regenerate this texture
10213         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10214         texture.basealpha = 1.0f;
10215         texture.currentskinframe = skinframe;
10216         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10217         texture.offsetmapping = OFFSETMAPPING_OFF;
10218         texture.offsetscale = 1;
10219         texture.specularscalemod = 1;
10220         texture.specularpowermod = 1;
10221         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10222
10223         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10224 }
10225
10226 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10227 {
10228         static msurface_t surface;
10229         const msurface_t *surfacelist = &surface;
10230
10231         // fake enough texture and surface state to render this geometry
10232         surface.texture = texture;
10233         surface.num_triangles = numtriangles;
10234         surface.num_firsttriangle = firsttriangle;
10235         surface.num_vertices = numvertices;
10236         surface.num_firstvertex = firstvertex;
10237
10238         // now render it
10239         rsurface.texture = R_GetCurrentTexture(surface.texture);
10240         rsurface.lightmaptexture = NULL;
10241         rsurface.deluxemaptexture = NULL;
10242         rsurface.uselightmaptexture = false;
10243         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10244 }