]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
gl: Fix r_lockpvs behaving like r_lockvisibility. Minor refactoring
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qbool r_loadnormalmap;
48 static qbool r_loadgloss;
49 qbool r_loadfog;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CF_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CF_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 = {CF_CLIENT | CF_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CF_CLIENT | CF_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
208 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
210
211 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
213
214 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
216 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
217 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
220
221 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CF_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 = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
229 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
230 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
231
232 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
233
234 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
235
236 cvar_t gl_lightmaps = {CF_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 = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
239
240 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
241 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
242 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
244
245 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
247
248 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
249
250 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
251 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
252 {
253         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
254         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
255         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
256         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
257 };
258
259 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
260 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
261 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
262
263 extern cvar_t v_glslgamma_2d;
264
265 extern qbool v_flipped_state;
266
267 r_framebufferstate_t r_fb;
268
269 /// shadow volume bsp struct with automatically growing nodes buffer
270 svbsp_t r_svbsp;
271
272 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
273
274 rtexture_t *r_texture_blanknormalmap;
275 rtexture_t *r_texture_white;
276 rtexture_t *r_texture_grey128;
277 rtexture_t *r_texture_black;
278 rtexture_t *r_texture_notexture;
279 rtexture_t *r_texture_whitecube;
280 rtexture_t *r_texture_normalizationcube;
281 rtexture_t *r_texture_fogattenuation;
282 rtexture_t *r_texture_fogheighttexture;
283 rtexture_t *r_texture_gammaramps;
284 unsigned int r_texture_gammaramps_serial;
285 //rtexture_t *r_texture_fogintensity;
286 rtexture_t *r_texture_reflectcube;
287
288 // TODO: hash lookups?
289 typedef struct cubemapinfo_s
290 {
291         char basename[64];
292         rtexture_t *texture;
293 }
294 cubemapinfo_t;
295
296 int r_texture_numcubemaps;
297 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
298
299 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
300 unsigned int r_numqueries;
301 unsigned int r_maxqueries;
302
303 typedef struct r_qwskincache_s
304 {
305         char name[MAX_QPATH];
306         skinframe_t *skinframe;
307 }
308 r_qwskincache_t;
309
310 static r_qwskincache_t *r_qwskincache;
311 static int r_qwskincache_size;
312
313 /// vertex coordinates for a quad that covers the screen exactly
314 extern const float r_screenvertex3f[12];
315 const float r_screenvertex3f[12] =
316 {
317         0, 0, 0,
318         1, 0, 0,
319         1, 1, 0,
320         0, 1, 0
321 };
322
323 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
324 {
325         int i;
326         for (i = 0;i < verts;i++)
327         {
328                 out[0] = in[0] * r;
329                 out[1] = in[1] * g;
330                 out[2] = in[2] * b;
331                 out[3] = in[3];
332                 in += 4;
333                 out += 4;
334         }
335 }
336
337 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
338 {
339         int i;
340         for (i = 0;i < verts;i++)
341         {
342                 out[0] = r;
343                 out[1] = g;
344                 out[2] = b;
345                 out[3] = a;
346                 out += 4;
347         }
348 }
349
350 // FIXME: move this to client?
351 void FOG_clear(void)
352 {
353         if (gamemode == GAME_NEHAHRA)
354         {
355                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
356                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
357                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
358                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
359                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
360         }
361         r_refdef.fog_density = 0;
362         r_refdef.fog_red = 0;
363         r_refdef.fog_green = 0;
364         r_refdef.fog_blue = 0;
365         r_refdef.fog_alpha = 1;
366         r_refdef.fog_start = 0;
367         r_refdef.fog_end = 16384;
368         r_refdef.fog_height = 1<<30;
369         r_refdef.fog_fadedepth = 128;
370         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
371 }
372
373 static void R_BuildBlankTextures(void)
374 {
375         unsigned char data[4];
376         data[2] = 128; // normal X
377         data[1] = 128; // normal Y
378         data[0] = 255; // normal Z
379         data[3] = 255; // height
380         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 255;
382         data[1] = 255;
383         data[2] = 255;
384         data[3] = 255;
385         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 128;
387         data[1] = 128;
388         data[2] = 128;
389         data[3] = 255;
390         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391         data[0] = 0;
392         data[1] = 0;
393         data[2] = 0;
394         data[3] = 255;
395         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
396 }
397
398 static void R_BuildNoTexture(void)
399 {
400         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
401 }
402
403 static void R_BuildWhiteCube(void)
404 {
405         unsigned char data[6*1*1*4];
406         memset(data, 255, sizeof(data));
407         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
408 }
409
410 static void R_BuildNormalizationCube(void)
411 {
412         int x, y, side;
413         vec3_t v;
414         vec_t s, t, intensity;
415 #define NORMSIZE 64
416         unsigned char *data;
417         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
418         for (side = 0;side < 6;side++)
419         {
420                 for (y = 0;y < NORMSIZE;y++)
421                 {
422                         for (x = 0;x < NORMSIZE;x++)
423                         {
424                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
425                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
426                                 switch(side)
427                                 {
428                                 default:
429                                 case 0:
430                                         v[0] = 1;
431                                         v[1] = -t;
432                                         v[2] = -s;
433                                         break;
434                                 case 1:
435                                         v[0] = -1;
436                                         v[1] = -t;
437                                         v[2] = s;
438                                         break;
439                                 case 2:
440                                         v[0] = s;
441                                         v[1] = 1;
442                                         v[2] = t;
443                                         break;
444                                 case 3:
445                                         v[0] = s;
446                                         v[1] = -1;
447                                         v[2] = -t;
448                                         break;
449                                 case 4:
450                                         v[0] = s;
451                                         v[1] = -t;
452                                         v[2] = 1;
453                                         break;
454                                 case 5:
455                                         v[0] = -s;
456                                         v[1] = -t;
457                                         v[2] = -1;
458                                         break;
459                                 }
460                                 intensity = 127.0f / sqrt(DotProduct(v, v));
461                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
462                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
463                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
464                                 data[((side*64+y)*64+x)*4+3] = 255;
465                         }
466                 }
467         }
468         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
469         Mem_Free(data);
470 }
471
472 static void R_BuildFogTexture(void)
473 {
474         int x, b;
475 #define FOGWIDTH 256
476         unsigned char data1[FOGWIDTH][4];
477         //unsigned char data2[FOGWIDTH][4];
478         double d, r, alpha;
479
480         r_refdef.fogmasktable_start = r_refdef.fog_start;
481         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
482         r_refdef.fogmasktable_range = r_refdef.fogrange;
483         r_refdef.fogmasktable_density = r_refdef.fog_density;
484
485         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
486         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
487         {
488                 d = (x * r - r_refdef.fogmasktable_start);
489                 if(developer_extra.integer)
490                         Con_DPrintf("%f ", d);
491                 d = max(0, d);
492                 if (r_fog_exp2.integer)
493                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
494                 else
495                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
496                 if(developer_extra.integer)
497                         Con_DPrintf(" : %f ", alpha);
498                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
499                 if(developer_extra.integer)
500                         Con_DPrintf(" = %f\n", alpha);
501                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
502         }
503
504         for (x = 0;x < FOGWIDTH;x++)
505         {
506                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
507                 data1[x][0] = b;
508                 data1[x][1] = b;
509                 data1[x][2] = b;
510                 data1[x][3] = 255;
511                 //data2[x][0] = 255 - b;
512                 //data2[x][1] = 255 - b;
513                 //data2[x][2] = 255 - b;
514                 //data2[x][3] = 255;
515         }
516         if (r_texture_fogattenuation)
517         {
518                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
519                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
520         }
521         else
522         {
523                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
524                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
525         }
526 }
527
528 static void R_BuildFogHeightTexture(void)
529 {
530         unsigned char *inpixels;
531         int size;
532         int x;
533         int y;
534         int j;
535         float c[4];
536         float f;
537         inpixels = NULL;
538         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
539         if (r_refdef.fogheighttexturename[0])
540                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
541         if (!inpixels)
542         {
543                 r_refdef.fog_height_tablesize = 0;
544                 if (r_texture_fogheighttexture)
545                         R_FreeTexture(r_texture_fogheighttexture);
546                 r_texture_fogheighttexture = NULL;
547                 if (r_refdef.fog_height_table2d)
548                         Mem_Free(r_refdef.fog_height_table2d);
549                 r_refdef.fog_height_table2d = NULL;
550                 if (r_refdef.fog_height_table1d)
551                         Mem_Free(r_refdef.fog_height_table1d);
552                 r_refdef.fog_height_table1d = NULL;
553                 return;
554         }
555         size = image_width;
556         r_refdef.fog_height_tablesize = size;
557         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
558         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
559         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
560         Mem_Free(inpixels);
561         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
562         // average fog color table accounting for every fog layer between a point
563         // and the camera.  (Note: attenuation is handled separately!)
564         for (y = 0;y < size;y++)
565         {
566                 for (x = 0;x < size;x++)
567                 {
568                         Vector4Clear(c);
569                         f = 0;
570                         if (x < y)
571                         {
572                                 for (j = x;j <= y;j++)
573                                 {
574                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
575                                         f++;
576                                 }
577                         }
578                         else
579                         {
580                                 for (j = x;j >= y;j--)
581                                 {
582                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
583                                         f++;
584                                 }
585                         }
586                         f = 1.0f / f;
587                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
588                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
589                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
590                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
591                 }
592         }
593         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
594 }
595
596 //=======================================================================================================================================================
597
598 static const char *builtinshaderstrings[] =
599 {
600 #include "shader_glsl.h"
601 0
602 };
603
604 //=======================================================================================================================================================
605
606 typedef struct shaderpermutationinfo_s
607 {
608         const char *pretext;
609         const char *name;
610 }
611 shaderpermutationinfo_t;
612
613 typedef struct shadermodeinfo_s
614 {
615         const char *sourcebasename;
616         const char *extension;
617         const char **builtinshaderstrings;
618         const char *pretext;
619         const char *name;
620         char *filename;
621         char *builtinstring;
622         int builtincrc;
623 }
624 shadermodeinfo_t;
625
626 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
627 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
628 {
629         {"#define USEDIFFUSE\n", " diffuse"},
630         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
631         {"#define USEVIEWTINT\n", " viewtint"},
632         {"#define USECOLORMAPPING\n", " colormapping"},
633         {"#define USESATURATION\n", " saturation"},
634         {"#define USEFOGINSIDE\n", " foginside"},
635         {"#define USEFOGOUTSIDE\n", " fogoutside"},
636         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
637         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
638         {"#define USEGAMMARAMPS\n", " gammaramps"},
639         {"#define USECUBEFILTER\n", " cubefilter"},
640         {"#define USEGLOW\n", " glow"},
641         {"#define USEBLOOM\n", " bloom"},
642         {"#define USESPECULAR\n", " specular"},
643         {"#define USEPOSTPROCESSING\n", " postprocessing"},
644         {"#define USEREFLECTION\n", " reflection"},
645         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
646         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
647         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
648         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
649         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
650         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
651         {"#define USEALPHAKILL\n", " alphakill"},
652         {"#define USEREFLECTCUBE\n", " reflectcube"},
653         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
654         {"#define USEBOUNCEGRID\n", " bouncegrid"},
655         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
656         {"#define USETRIPPY\n", " trippy"},
657         {"#define USEDEPTHRGB\n", " depthrgb"},
658         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
659         {"#define USESKELETAL\n", " skeletal"},
660         {"#define USEOCCLUDE\n", " occlude"}
661 };
662
663 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
664 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
665 {
666         // SHADERLANGUAGE_GLSL
667         {
668                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
669                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
683                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
684                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
685         },
686 };
687
688 struct r_glsl_permutation_s;
689 typedef struct r_glsl_permutation_s
690 {
691         /// hash lookup data
692         struct r_glsl_permutation_s *hashnext;
693         unsigned int mode;
694         uint64_t permutation;
695
696         /// indicates if we have tried compiling this permutation already
697         qbool compiled;
698         /// 0 if compilation failed
699         int program;
700         // texture units assigned to each detected uniform
701         int tex_Texture_First;
702         int tex_Texture_Second;
703         int tex_Texture_GammaRamps;
704         int tex_Texture_Normal;
705         int tex_Texture_Color;
706         int tex_Texture_Gloss;
707         int tex_Texture_Glow;
708         int tex_Texture_SecondaryNormal;
709         int tex_Texture_SecondaryColor;
710         int tex_Texture_SecondaryGloss;
711         int tex_Texture_SecondaryGlow;
712         int tex_Texture_Pants;
713         int tex_Texture_Shirt;
714         int tex_Texture_FogHeightTexture;
715         int tex_Texture_FogMask;
716         int tex_Texture_LightGrid;
717         int tex_Texture_Lightmap;
718         int tex_Texture_Deluxemap;
719         int tex_Texture_Attenuation;
720         int tex_Texture_Cube;
721         int tex_Texture_Refraction;
722         int tex_Texture_Reflection;
723         int tex_Texture_ShadowMap2D;
724         int tex_Texture_CubeProjection;
725         int tex_Texture_ScreenNormalMap;
726         int tex_Texture_ScreenDiffuse;
727         int tex_Texture_ScreenSpecular;
728         int tex_Texture_ReflectMask;
729         int tex_Texture_ReflectCube;
730         int tex_Texture_BounceGrid;
731         /// locations of detected uniforms in program object, or -1 if not found
732         int loc_Texture_First;
733         int loc_Texture_Second;
734         int loc_Texture_GammaRamps;
735         int loc_Texture_Normal;
736         int loc_Texture_Color;
737         int loc_Texture_Gloss;
738         int loc_Texture_Glow;
739         int loc_Texture_SecondaryNormal;
740         int loc_Texture_SecondaryColor;
741         int loc_Texture_SecondaryGloss;
742         int loc_Texture_SecondaryGlow;
743         int loc_Texture_Pants;
744         int loc_Texture_Shirt;
745         int loc_Texture_FogHeightTexture;
746         int loc_Texture_FogMask;
747         int loc_Texture_LightGrid;
748         int loc_Texture_Lightmap;
749         int loc_Texture_Deluxemap;
750         int loc_Texture_Attenuation;
751         int loc_Texture_Cube;
752         int loc_Texture_Refraction;
753         int loc_Texture_Reflection;
754         int loc_Texture_ShadowMap2D;
755         int loc_Texture_CubeProjection;
756         int loc_Texture_ScreenNormalMap;
757         int loc_Texture_ScreenDiffuse;
758         int loc_Texture_ScreenSpecular;
759         int loc_Texture_ReflectMask;
760         int loc_Texture_ReflectCube;
761         int loc_Texture_BounceGrid;
762         int loc_Alpha;
763         int loc_BloomBlur_Parameters;
764         int loc_ClientTime;
765         int loc_Color_Ambient;
766         int loc_Color_Diffuse;
767         int loc_Color_Specular;
768         int loc_Color_Glow;
769         int loc_Color_Pants;
770         int loc_Color_Shirt;
771         int loc_DeferredColor_Ambient;
772         int loc_DeferredColor_Diffuse;
773         int loc_DeferredColor_Specular;
774         int loc_DeferredMod_Diffuse;
775         int loc_DeferredMod_Specular;
776         int loc_DistortScaleRefractReflect;
777         int loc_EyePosition;
778         int loc_FogColor;
779         int loc_FogHeightFade;
780         int loc_FogPlane;
781         int loc_FogPlaneViewDist;
782         int loc_FogRangeRecip;
783         int loc_LightColor;
784         int loc_LightDir;
785         int loc_LightGridMatrix;
786         int loc_LightGridNormalMatrix;
787         int loc_LightPosition;
788         int loc_OffsetMapping_ScaleSteps;
789         int loc_OffsetMapping_LodDistance;
790         int loc_OffsetMapping_Bias;
791         int loc_PixelSize;
792         int loc_ReflectColor;
793         int loc_ReflectFactor;
794         int loc_ReflectOffset;
795         int loc_RefractColor;
796         int loc_Saturation;
797         int loc_ScreenCenterRefractReflect;
798         int loc_ScreenScaleRefractReflect;
799         int loc_ScreenToDepth;
800         int loc_ShadowMap_Parameters;
801         int loc_ShadowMap_TextureScale;
802         int loc_SpecularPower;
803         int loc_Skeletal_Transform12;
804         int loc_UserVec1;
805         int loc_UserVec2;
806         int loc_UserVec3;
807         int loc_UserVec4;
808         int loc_ColorFringe;
809         int loc_ViewTintColor;
810         int loc_ViewToLight;
811         int loc_ModelToLight;
812         int loc_TexMatrix;
813         int loc_BackgroundTexMatrix;
814         int loc_ModelViewProjectionMatrix;
815         int loc_ModelViewMatrix;
816         int loc_PixelToScreenTexCoord;
817         int loc_ModelToReflectCube;
818         int loc_ShadowMapMatrix;
819         int loc_BloomColorSubtract;
820         int loc_NormalmapScrollBlend;
821         int loc_BounceGridMatrix;
822         int loc_BounceGridIntensity;
823         /// uniform block bindings
824         int ubibind_Skeletal_Transform12_UniformBlock;
825         /// uniform block indices
826         int ubiloc_Skeletal_Transform12_UniformBlock;
827 }
828 r_glsl_permutation_t;
829
830 #define SHADERPERMUTATION_HASHSIZE 256
831
832
833 // non-degradable "lightweight" shader parameters to keep the permutations simpler
834 // these can NOT degrade! only use for simple stuff
835 enum
836 {
837         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
838         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
839         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
840         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
841         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
842         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
843         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
844         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
845         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
846         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
847         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
848         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
849         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
850         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
851 };
852 #define SHADERSTATICPARMS_COUNT 14
853
854 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
855 static int shaderstaticparms_count = 0;
856
857 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
858 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
859
860 extern qbool r_shadow_shadowmapsampler;
861 extern int r_shadow_shadowmappcf;
862 qbool R_CompileShader_CheckStaticParms(void)
863 {
864         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
865         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
866         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
867
868         // detect all
869         if (r_glsl_saturation_redcompensate.integer)
870                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
871         if (r_glsl_vertextextureblend_usebothalphas.integer)
872                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
873         if (r_shadow_glossexact.integer)
874                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
875         if (r_glsl_postprocess.integer)
876         {
877                 if (r_glsl_postprocess_uservec1_enable.integer)
878                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
879                 if (r_glsl_postprocess_uservec2_enable.integer)
880                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
881                 if (r_glsl_postprocess_uservec3_enable.integer)
882                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
883                 if (r_glsl_postprocess_uservec4_enable.integer)
884                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
885         }
886         if (r_fxaa.integer)
887                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
888         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
889                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
890
891         if (r_shadow_shadowmapsampler)
892                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
893         if (r_shadow_shadowmappcf > 1)
894                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
895         else if (r_shadow_shadowmappcf)
896                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
897         if (r_celshading.integer)
898                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
899         if (r_celoutlines.integer)
900                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
901
902         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
903 }
904
905 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
906         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
907                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
908         else \
909                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
910 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
911 {
912         shaderstaticparms_count = 0;
913
914         // emit all
915         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
916         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
917         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
918         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
919         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
929 }
930
931 /// information about each possible shader permutation
932 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
933 /// currently selected permutation
934 r_glsl_permutation_t *r_glsl_permutation;
935 /// storage for permutations linked in the hash table
936 memexpandablearray_t r_glsl_permutationarray;
937
938 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
939 {
940         //unsigned int hashdepth = 0;
941         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
942         r_glsl_permutation_t *p;
943         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
944         {
945                 if (p->mode == mode && p->permutation == permutation)
946                 {
947                         //if (hashdepth > 10)
948                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
949                         return p;
950                 }
951                 //hashdepth++;
952         }
953         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
954         p->mode = mode;
955         p->permutation = permutation;
956         p->hashnext = r_glsl_permutationhash[mode][hashindex];
957         r_glsl_permutationhash[mode][hashindex] = p;
958         //if (hashdepth > 10)
959         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
960         return p;
961 }
962
963 static char *R_ShaderStrCat(const char **strings)
964 {
965         char *string, *s;
966         const char **p = strings;
967         const char *t;
968         size_t len = 0;
969         for (p = strings;(t = *p);p++)
970                 len += strlen(t);
971         len++;
972         s = string = (char *)Mem_Alloc(r_main_mempool, len);
973         len = 0;
974         for (p = strings;(t = *p);p++)
975         {
976                 len = strlen(t);
977                 memcpy(s, t, len);
978                 s += len;
979         }
980         *s = 0;
981         return string;
982 }
983
984 static char *R_ShaderStrCat(const char **strings);
985 static void R_InitShaderModeInfo(void)
986 {
987         int i, language;
988         shadermodeinfo_t *modeinfo;
989         // 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)
990         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
991         {
992                 for (i = 0; i < SHADERMODE_COUNT; i++)
993                 {
994                         char filename[MAX_QPATH];
995                         modeinfo = &shadermodeinfo[language][i];
996                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
997                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
998                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
999                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1000                 }
1001         }
1002 }
1003
1004 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1005 {
1006         char *shaderstring;
1007         // if the mode has no filename we have to return the builtin string
1008         if (builtinonly || !modeinfo->filename)
1009                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1010         // note that FS_LoadFile appends a 0 byte to make it a valid string
1011         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1012         if (shaderstring)
1013         {
1014                 if (printfromdisknotice)
1015                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1016                 return shaderstring;
1017         }
1018         // fall back to builtinstring
1019         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1020 }
1021
1022 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1023 {
1024         int i;
1025         int ubibind;
1026         int sampler;
1027         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1028         char *sourcestring;
1029         char permutationname[256];
1030         int vertstrings_count = 0;
1031         int geomstrings_count = 0;
1032         int fragstrings_count = 0;
1033         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1034         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1035         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1036
1037         if (p->compiled)
1038                 return;
1039         p->compiled = true;
1040         p->program = 0;
1041
1042         permutationname[0] = 0;
1043         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1044
1045         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1046
1047         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1048         if(vid.support.glshaderversion >= 140)
1049         {
1050                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1051                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1052                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1053                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1054                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1055                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1056         }
1057         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1058         else if(vid.support.glshaderversion >= 130)
1059         {
1060                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1061                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1062                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1063                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1064                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1065                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1066         }
1067         // if we can do #version 120, we should (this adds the invariant keyword)
1068         else if(vid.support.glshaderversion >= 120)
1069         {
1070                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1071                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1072                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1073                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1074                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1075                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1076         }
1077         // GLES also adds several things from GLSL120
1078         switch(vid.renderpath)
1079         {
1080         case RENDERPATH_GLES2:
1081                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1082                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1083                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1084                 break;
1085         default:
1086                 break;
1087         }
1088
1089         // the first pretext is which type of shader to compile as
1090         // (later these will all be bound together as a program object)
1091         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1092         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1093         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1094
1095         // the second pretext is the mode (for example a light source)
1096         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1097         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1098         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1099         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1100
1101         // now add all the permutation pretexts
1102         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1103         {
1104                 if (permutation & (1ll<<i))
1105                 {
1106                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1107                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1108                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1109                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1110                 }
1111                 else
1112                 {
1113                         // keep line numbers correct
1114                         vertstrings_list[vertstrings_count++] = "\n";
1115                         geomstrings_list[geomstrings_count++] = "\n";
1116                         fragstrings_list[fragstrings_count++] = "\n";
1117                 }
1118         }
1119
1120         // add static parms
1121         R_CompileShader_AddStaticParms(mode, permutation);
1122         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1123         vertstrings_count += shaderstaticparms_count;
1124         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1125         geomstrings_count += shaderstaticparms_count;
1126         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1127         fragstrings_count += shaderstaticparms_count;
1128
1129         // now append the shader text itself
1130         vertstrings_list[vertstrings_count++] = sourcestring;
1131         geomstrings_list[geomstrings_count++] = sourcestring;
1132         fragstrings_list[fragstrings_count++] = sourcestring;
1133
1134         // we don't currently use geometry shaders for anything, so just empty the list
1135         geomstrings_count = 0;
1136
1137         // compile the shader program
1138         if (vertstrings_count + geomstrings_count + fragstrings_count)
1139                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1140         if (p->program)
1141         {
1142                 CHECKGLERROR
1143                 qglUseProgram(p->program);CHECKGLERROR
1144                 // look up all the uniform variable names we care about, so we don't
1145                 // have to look them up every time we set them
1146
1147 #if 0
1148                 // debugging aid
1149                 {
1150                         GLint activeuniformindex = 0;
1151                         GLint numactiveuniforms = 0;
1152                         char uniformname[128];
1153                         GLsizei uniformnamelength = 0;
1154                         GLint uniformsize = 0;
1155                         GLenum uniformtype = 0;
1156                         memset(uniformname, 0, sizeof(uniformname));
1157                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1158                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1159                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1160                         {
1161                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1162                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1163                         }
1164                 }
1165 #endif
1166
1167                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1168                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1169                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1170                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1171                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1172                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1173                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1174                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1175                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1176                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1177                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1178                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1179                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1180                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1181                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1182                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1183                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1184                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1185                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1186                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1187                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1188                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1189                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1190                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1191                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1192                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1193                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1194                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1195                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1196                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1197                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1198                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1199                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1200                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1201                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1202                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1203                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1204                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1205                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1206                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1207                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1208                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1209                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1210                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1211                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1212                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1213                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1214                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1215                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1216                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1217                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1218                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1219                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1220                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1221                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1222                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1223                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1224                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1225                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1226                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1227                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1228                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1229                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1230                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1231                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1232                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1233                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1234                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1235                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1236                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1237                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1238                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1239                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1240                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1241                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1242                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1243                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1244                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1245                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1246                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1247                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1248                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1249                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1250                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1251                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1252                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1253                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1254                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1255                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1256                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1257                 // initialize the samplers to refer to the texture units we use
1258                 p->tex_Texture_First = -1;
1259                 p->tex_Texture_Second = -1;
1260                 p->tex_Texture_GammaRamps = -1;
1261                 p->tex_Texture_Normal = -1;
1262                 p->tex_Texture_Color = -1;
1263                 p->tex_Texture_Gloss = -1;
1264                 p->tex_Texture_Glow = -1;
1265                 p->tex_Texture_SecondaryNormal = -1;
1266                 p->tex_Texture_SecondaryColor = -1;
1267                 p->tex_Texture_SecondaryGloss = -1;
1268                 p->tex_Texture_SecondaryGlow = -1;
1269                 p->tex_Texture_Pants = -1;
1270                 p->tex_Texture_Shirt = -1;
1271                 p->tex_Texture_FogHeightTexture = -1;
1272                 p->tex_Texture_FogMask = -1;
1273                 p->tex_Texture_LightGrid = -1;
1274                 p->tex_Texture_Lightmap = -1;
1275                 p->tex_Texture_Deluxemap = -1;
1276                 p->tex_Texture_Attenuation = -1;
1277                 p->tex_Texture_Cube = -1;
1278                 p->tex_Texture_Refraction = -1;
1279                 p->tex_Texture_Reflection = -1;
1280                 p->tex_Texture_ShadowMap2D = -1;
1281                 p->tex_Texture_CubeProjection = -1;
1282                 p->tex_Texture_ScreenNormalMap = -1;
1283                 p->tex_Texture_ScreenDiffuse = -1;
1284                 p->tex_Texture_ScreenSpecular = -1;
1285                 p->tex_Texture_ReflectMask = -1;
1286                 p->tex_Texture_ReflectCube = -1;
1287                 p->tex_Texture_BounceGrid = -1;
1288                 // bind the texture samplers in use
1289                 sampler = 0;
1290                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1291                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1292                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1293                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1294                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1295                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1296                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1297                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1298                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1299                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1300                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1301                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1302                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1303                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1304                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1305                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1306                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1307                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1308                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1309                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1310                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1311                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1312                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1313                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1314                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1315                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1316                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1317                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1318                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1319                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1320                 // get the uniform block indices so we can bind them
1321                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1322 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1323                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1324 #endif
1325                 // clear the uniform block bindings
1326                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1327                 // bind the uniform blocks in use
1328                 ubibind = 0;
1329 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1330                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1331 #endif
1332                 // we're done compiling and setting up the shader, at least until it is used
1333                 CHECKGLERROR
1334                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1335         }
1336         else
1337                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1338
1339         // free the strings
1340         if (sourcestring)
1341                 Mem_Free(sourcestring);
1342 }
1343
1344 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1345 {
1346         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1347         if (r_glsl_permutation != perm)
1348         {
1349                 r_glsl_permutation = perm;
1350                 if (!r_glsl_permutation->program)
1351                 {
1352                         if (!r_glsl_permutation->compiled)
1353                         {
1354                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1355                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1356                         }
1357                         if (!r_glsl_permutation->program)
1358                         {
1359                                 // remove features until we find a valid permutation
1360                                 int i;
1361                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1362                                 {
1363                                         // reduce i more quickly whenever it would not remove any bits
1364                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1365                                         if (!(permutation & j))
1366                                                 continue;
1367                                         permutation -= j;
1368                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1369                                         if (!r_glsl_permutation->compiled)
1370                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1371                                         if (r_glsl_permutation->program)
1372                                                 break;
1373                                 }
1374                                 if (i >= SHADERPERMUTATION_COUNT)
1375                                 {
1376                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1377                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1378                                         qglUseProgram(0);CHECKGLERROR
1379                                         return; // no bit left to clear, entire mode is broken
1380                                 }
1381                         }
1382                 }
1383                 CHECKGLERROR
1384                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1385         }
1386         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1387         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1388         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1389         CHECKGLERROR
1390 }
1391
1392 void R_GLSL_Restart_f(cmd_state_t *cmd)
1393 {
1394         unsigned int i, limit;
1395         switch(vid.renderpath)
1396         {
1397         case RENDERPATH_GL32:
1398         case RENDERPATH_GLES2:
1399                 {
1400                         r_glsl_permutation_t *p;
1401                         r_glsl_permutation = NULL;
1402                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1403                         for (i = 0;i < limit;i++)
1404                         {
1405                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1406                                 {
1407                                         GL_Backend_FreeProgram(p->program);
1408                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1409                                 }
1410                         }
1411                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1412                 }
1413                 break;
1414         }
1415 }
1416
1417 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1418 {
1419         int i, language, mode, dupe;
1420         char *text;
1421         shadermodeinfo_t *modeinfo;
1422         qfile_t *file;
1423
1424         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1425         {
1426                 modeinfo = shadermodeinfo[language];
1427                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1428                 {
1429                         // don't dump the same file multiple times (most or all shaders come from the same file)
1430                         for (dupe = mode - 1;dupe >= 0;dupe--)
1431                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1432                                         break;
1433                         if (dupe >= 0)
1434                                 continue;
1435                         text = modeinfo[mode].builtinstring;
1436                         if (!text)
1437                                 continue;
1438                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1439                         if (file)
1440                         {
1441                                 FS_Print(file, "/* The engine may define the following macros:\n");
1442                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1443                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1444                                         FS_Print(file, modeinfo[i].pretext);
1445                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1446                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1447                                 FS_Print(file, "*/\n");
1448                                 FS_Print(file, text);
1449                                 FS_Close(file);
1450                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1451                         }
1452                         else
1453                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1454                 }
1455         }
1456 }
1457
1458 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1459 {
1460         uint64_t permutation = 0;
1461         if (r_trippy.integer && !notrippy)
1462                 permutation |= SHADERPERMUTATION_TRIPPY;
1463         permutation |= SHADERPERMUTATION_VIEWTINT;
1464         if (t)
1465                 permutation |= SHADERPERMUTATION_DIFFUSE;
1466         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1467                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1468         if (suppresstexalpha)
1469                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1470         if (vid.allowalphatocoverage)
1471                 GL_AlphaToCoverage(false);
1472         switch (vid.renderpath)
1473         {
1474         case RENDERPATH_GL32:
1475         case RENDERPATH_GLES2:
1476                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1477                 if (r_glsl_permutation->tex_Texture_First >= 0)
1478                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1479                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1480                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1481                 break;
1482         }
1483 }
1484
1485 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1486 {
1487         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1488 }
1489
1490 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1491 {
1492         uint64_t permutation = 0;
1493         if (r_trippy.integer && !notrippy)
1494                 permutation |= SHADERPERMUTATION_TRIPPY;
1495         if (depthrgb)
1496                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1497         if (skeletal)
1498                 permutation |= SHADERPERMUTATION_SKELETAL;
1499
1500         if (vid.allowalphatocoverage)
1501                 GL_AlphaToCoverage(false);
1502         switch (vid.renderpath)
1503         {
1504         case RENDERPATH_GL32:
1505         case RENDERPATH_GLES2:
1506                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1507 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1508                 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);
1509 #endif
1510                 break;
1511         }
1512 }
1513
1514 #define BLENDFUNC_ALLOWS_COLORMOD      1
1515 #define BLENDFUNC_ALLOWS_FOG           2
1516 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1517 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1518 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1519 static int R_BlendFuncFlags(int src, int dst)
1520 {
1521         int r = 0;
1522
1523         // a blendfunc allows colormod if:
1524         // a) it can never keep the destination pixel invariant, or
1525         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1526         // this is to prevent unintended side effects from colormod
1527
1528         // a blendfunc allows fog if:
1529         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1530         // this is to prevent unintended side effects from fog
1531
1532         // these checks are the output of fogeval.pl
1533
1534         r |= BLENDFUNC_ALLOWS_COLORMOD;
1535         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1536         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1537         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1538         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1539         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1540         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1541         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1542         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1543         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1544         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1545         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1546         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1547         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1548         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1549         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1550         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1551         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1552         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1553         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1555         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556
1557         return r;
1558 }
1559
1560 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qbool notrippy, qbool ui)
1561 {
1562         // select a permutation of the lighting shader appropriate to this
1563         // combination of texture, entity, light source, and fogging, only use the
1564         // minimum features necessary to avoid wasting rendering time in the
1565         // fragment shader on features that are not being used
1566         uint64_t permutation = 0;
1567         unsigned int mode = 0;
1568         int blendfuncflags;
1569         texture_t *t = rsurface.texture;
1570         float m16f[16];
1571         matrix4x4_t tempmatrix;
1572         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1573         if (r_trippy.integer && !notrippy)
1574                 permutation |= SHADERPERMUTATION_TRIPPY;
1575         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1576                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1577         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1578                 permutation |= SHADERPERMUTATION_OCCLUDE;
1579         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1580                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1581         if (rsurfacepass == RSURFPASS_BACKGROUND)
1582         {
1583                 // distorted background
1584                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1585                 {
1586                         mode = SHADERMODE_WATER;
1587                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1588                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1589                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1590                         {
1591                                 // this is the right thing to do for wateralpha
1592                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1593                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1594                         }
1595                         else
1596                         {
1597                                 // this is the right thing to do for entity alpha
1598                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1599                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1600                         }
1601                 }
1602                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1603                 {
1604                         mode = SHADERMODE_REFRACTION;
1605                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1606                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1607                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1608                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1609                 }
1610                 else
1611                 {
1612                         mode = SHADERMODE_GENERIC;
1613                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1614                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1615                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1616                 }
1617                 if (vid.allowalphatocoverage)
1618                         GL_AlphaToCoverage(false);
1619         }
1620         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1621         {
1622                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1623                 {
1624                         switch(t->offsetmapping)
1625                         {
1626                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1627                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1628                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1629                         case OFFSETMAPPING_OFF: break;
1630                         }
1631                 }
1632                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1633                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1634                 // normalmap (deferred prepass), may use alpha test on diffuse
1635                 mode = SHADERMODE_DEFERREDGEOMETRY;
1636                 GL_BlendFunc(GL_ONE, GL_ZERO);
1637                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1638                 if (vid.allowalphatocoverage)
1639                         GL_AlphaToCoverage(false);
1640         }
1641         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1642         {
1643                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1644                 {
1645                         switch(t->offsetmapping)
1646                         {
1647                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1648                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1649                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1650                         case OFFSETMAPPING_OFF: break;
1651                         }
1652                 }
1653                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1654                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1655                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1656                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1657                 // light source
1658                 mode = SHADERMODE_LIGHTSOURCE;
1659                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1660                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1661                 if (VectorLength2(rtlightdiffuse) > 0)
1662                         permutation |= SHADERPERMUTATION_DIFFUSE;
1663                 if (VectorLength2(rtlightspecular) > 0)
1664                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1665                 if (r_refdef.fogenabled)
1666                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1667                 if (t->colormapping)
1668                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1669                 if (r_shadow_usingshadowmap2d)
1670                 {
1671                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1672                         if(r_shadow_shadowmapvsdct)
1673                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1674
1675                         if (r_shadow_shadowmap2ddepthbuffer)
1676                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1677                 }
1678                 if (t->reflectmasktexture)
1679                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1680                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1681                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1682                 if (vid.allowalphatocoverage)
1683                         GL_AlphaToCoverage(false);
1684         }
1685         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1686         {
1687                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1688                 {
1689                         switch(t->offsetmapping)
1690                         {
1691                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1692                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1693                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1694                         case OFFSETMAPPING_OFF: break;
1695                         }
1696                 }
1697                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1698                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1699                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1700                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1701                 // directional model lighting
1702                 mode = SHADERMODE_LIGHTGRID;
1703                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1704                         permutation |= SHADERPERMUTATION_GLOW;
1705                 permutation |= SHADERPERMUTATION_DIFFUSE;
1706                 if (t->glosstexture || t->backgroundglosstexture)
1707                         permutation |= SHADERPERMUTATION_SPECULAR;
1708                 if (r_refdef.fogenabled)
1709                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1710                 if (t->colormapping)
1711                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1712                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1713                 {
1714                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1715                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1716
1717                         if (r_shadow_shadowmap2ddepthbuffer)
1718                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1719                 }
1720                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1721                         permutation |= SHADERPERMUTATION_REFLECTION;
1722                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1723                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1724                 if (t->reflectmasktexture)
1725                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1726                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1727                 {
1728                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1729                         if (r_shadow_bouncegrid_state.directional)
1730                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1731                 }
1732                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1733                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1734                 // when using alphatocoverage, we don't need alphakill
1735                 if (vid.allowalphatocoverage)
1736                 {
1737                         if (r_transparent_alphatocoverage.integer)
1738                         {
1739                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1740                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1741                         }
1742                         else
1743                                 GL_AlphaToCoverage(false);
1744                 }
1745         }
1746         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1747         {
1748                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1749                 {
1750                         switch(t->offsetmapping)
1751                         {
1752                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1753                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1754                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1755                         case OFFSETMAPPING_OFF: break;
1756                         }
1757                 }
1758                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1759                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1760                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1761                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1762                 // directional model lighting
1763                 mode = SHADERMODE_LIGHTDIRECTION;
1764                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1765                         permutation |= SHADERPERMUTATION_GLOW;
1766                 if (VectorLength2(t->render_modellight_diffuse))
1767                         permutation |= SHADERPERMUTATION_DIFFUSE;
1768                 if (VectorLength2(t->render_modellight_specular) > 0)
1769                         permutation |= SHADERPERMUTATION_SPECULAR;
1770                 if (r_refdef.fogenabled)
1771                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1772                 if (t->colormapping)
1773                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1774                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1775                 {
1776                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1777                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1778
1779                         if (r_shadow_shadowmap2ddepthbuffer)
1780                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1781                 }
1782                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1783                         permutation |= SHADERPERMUTATION_REFLECTION;
1784                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1785                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1786                 if (t->reflectmasktexture)
1787                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1788                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1789                 {
1790                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1791                         if (r_shadow_bouncegrid_state.directional)
1792                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1793                 }
1794                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1795                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1796                 // when using alphatocoverage, we don't need alphakill
1797                 if (vid.allowalphatocoverage)
1798                 {
1799                         if (r_transparent_alphatocoverage.integer)
1800                         {
1801                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1802                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1803                         }
1804                         else
1805                                 GL_AlphaToCoverage(false);
1806                 }
1807         }
1808         else
1809         {
1810                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1811                 {
1812                         switch(t->offsetmapping)
1813                         {
1814                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1815                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1816                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1817                         case OFFSETMAPPING_OFF: break;
1818                         }
1819                 }
1820                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1821                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1822                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1823                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1824                 // lightmapped wall
1825                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1826                         permutation |= SHADERPERMUTATION_GLOW;
1827                 if (r_refdef.fogenabled && !ui)
1828                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1829                 if (t->colormapping)
1830                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1831                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1832                 {
1833                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1834                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1835
1836                         if (r_shadow_shadowmap2ddepthbuffer)
1837                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1838                 }
1839                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1840                         permutation |= SHADERPERMUTATION_REFLECTION;
1841                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1842                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1843                 if (t->reflectmasktexture)
1844                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1845                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1846                 {
1847                         // deluxemapping (light direction texture)
1848                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1849                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1850                         else
1851                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1852                         permutation |= SHADERPERMUTATION_DIFFUSE;
1853                         if (VectorLength2(t->render_lightmap_specular) > 0)
1854                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1855                 }
1856                 else if (r_glsl_deluxemapping.integer >= 2)
1857                 {
1858                         // fake deluxemapping (uniform light direction in tangentspace)
1859                         if (rsurface.uselightmaptexture)
1860                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1861                         else
1862                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1863                         permutation |= SHADERPERMUTATION_DIFFUSE;
1864                         if (VectorLength2(t->render_lightmap_specular) > 0)
1865                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1866                 }
1867                 else if (rsurface.uselightmaptexture)
1868                 {
1869                         // ordinary lightmapping (q1bsp, q3bsp)
1870                         mode = SHADERMODE_LIGHTMAP;
1871                 }
1872                 else
1873                 {
1874                         // ordinary vertex coloring (q3bsp)
1875                         mode = SHADERMODE_VERTEXCOLOR;
1876                 }
1877                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1878                 {
1879                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1880                         if (r_shadow_bouncegrid_state.directional)
1881                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1882                 }
1883                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1884                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1885                 // when using alphatocoverage, we don't need alphakill
1886                 if (vid.allowalphatocoverage)
1887                 {
1888                         if (r_transparent_alphatocoverage.integer)
1889                         {
1890                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1891                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1892                         }
1893                         else
1894                                 GL_AlphaToCoverage(false);
1895                 }
1896         }
1897         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1898                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1899         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1900                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1901         switch(vid.renderpath)
1902         {
1903         case RENDERPATH_GL32:
1904         case RENDERPATH_GLES2:
1905                 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);
1906                 RSurf_UploadBuffersForBatch();
1907                 // this has to be after RSurf_PrepareVerticesForBatch
1908                 if (rsurface.batchskeletaltransform3x4buffer)
1909                         permutation |= SHADERPERMUTATION_SKELETAL;
1910                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1911 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1912                 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);
1913 #endif
1914                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1915                 if (mode == SHADERMODE_LIGHTSOURCE)
1916                 {
1917                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1918                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1919                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1920                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1921                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1922                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1923         
1924                         // additive passes are only darkened by fog, not tinted
1925                         if (r_glsl_permutation->loc_FogColor >= 0)
1926                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1927                         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);
1928                 }
1929                 else
1930                 {
1931                         if (mode == SHADERMODE_FLATCOLOR)
1932                         {
1933                                 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]);
1934                         }
1935                         else if (mode == SHADERMODE_LIGHTGRID)
1936                         {
1937                                 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]);
1938                                 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]);
1939                                 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]);
1940                                 // other LightGrid uniforms handled below
1941                         }
1942                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1943                         {
1944                                 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]);
1945                                 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]);
1946                                 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]);
1947                                 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]);
1948                                 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]);
1949                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1950                                 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]);
1951                         }
1952                         else
1953                         {
1954                                 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]);
1955                                 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]);
1956                                 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]);
1957                                 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]);
1958                                 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]);
1959                         }
1960                         // additive passes are only darkened by fog, not tinted
1961                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1962                         {
1963                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1964                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1965                                 else
1966                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1967                         }
1968                         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);
1969                         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]);
1970                         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]);
1971                         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);
1972                         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);
1973                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1974                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1975                         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);
1976                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1977                 }
1978                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1979                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1980                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1981                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1982                 {
1983                         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]);
1984                         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]);
1985                 }
1986                 else
1987                 {
1988                         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]);
1989                         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]);
1990                 }
1991
1992                 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]);
1993                 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));
1994                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1995                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1996                 {
1997                         if (t->pantstexture)
1998                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1999                         else
2000                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2001                 }
2002                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2003                 {
2004                         if (t->shirttexture)
2005                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2006                         else
2007                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2008                 }
2009                 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]);
2010                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2011                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2012                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2013                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2014                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2015                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2016                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2017                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2018                         );
2019                 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);
2020                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2021                 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]);
2022                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2023                 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);}
2024                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2025                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2026                 {
2027                         float m9f[9];
2028                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2029                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2030                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2031                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2032                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2033                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2034                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2035                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2036                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2037                 }
2038
2039                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2040                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2041                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2042                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2043                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2044                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2045                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2046                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2047                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2048                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2049                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2050                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2051                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2052                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2053                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2054                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2055                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2056                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2057                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2058                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2059                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2060                 {
2061                         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);
2062                         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);
2063                         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);
2064                 }
2065                 else
2066                 {
2067                         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);
2068                 }
2069                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2070                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2071                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2072                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2073                 {
2074                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2075                         if (rsurface.rtlight)
2076                         {
2077                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2078                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2079                         }
2080                 }
2081                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2082                 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);
2083                 CHECKGLERROR
2084                 break;
2085         }
2086 }
2087
2088 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2089 {
2090         // select a permutation of the lighting shader appropriate to this
2091         // combination of texture, entity, light source, and fogging, only use the
2092         // minimum features necessary to avoid wasting rendering time in the
2093         // fragment shader on features that are not being used
2094         uint64_t permutation = 0;
2095         unsigned int mode = 0;
2096         const float *lightcolorbase = rtlight->currentcolor;
2097         float ambientscale = rtlight->ambientscale;
2098         float diffusescale = rtlight->diffusescale;
2099         float specularscale = rtlight->specularscale;
2100         // this is the location of the light in view space
2101         vec3_t viewlightorigin;
2102         // this transforms from view space (camera) to light space (cubemap)
2103         matrix4x4_t viewtolight;
2104         matrix4x4_t lighttoview;
2105         float viewtolight16f[16];
2106         // light source
2107         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2108         if (rtlight->currentcubemap != r_texture_whitecube)
2109                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2110         if (diffusescale > 0)
2111                 permutation |= SHADERPERMUTATION_DIFFUSE;
2112         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2113                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2114         if (r_shadow_usingshadowmap2d)
2115         {
2116                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2117                 if (r_shadow_shadowmapvsdct)
2118                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2119
2120                 if (r_shadow_shadowmap2ddepthbuffer)
2121                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2122         }
2123         if (vid.allowalphatocoverage)
2124                 GL_AlphaToCoverage(false);
2125         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2126         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2127         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2128         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2129         switch(vid.renderpath)
2130         {
2131         case RENDERPATH_GL32:
2132         case RENDERPATH_GLES2:
2133                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2134                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2135                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2136                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2137                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2138                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2139                 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]);
2140                 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]);
2141                 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);
2142                 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]);
2143                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2144
2145                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2146                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2147                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2148                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2149                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2150                 break;
2151         }
2152 }
2153
2154 #define SKINFRAME_HASH 1024
2155
2156 typedef struct
2157 {
2158         unsigned int loadsequence; // incremented each level change
2159         memexpandablearray_t array;
2160         skinframe_t *hash[SKINFRAME_HASH];
2161 }
2162 r_skinframe_t;
2163 r_skinframe_t r_skinframe;
2164
2165 void R_SkinFrame_PrepareForPurge(void)
2166 {
2167         r_skinframe.loadsequence++;
2168         // wrap it without hitting zero
2169         if (r_skinframe.loadsequence >= 200)
2170                 r_skinframe.loadsequence = 1;
2171 }
2172
2173 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2174 {
2175         if (!skinframe)
2176                 return;
2177         // mark the skinframe as used for the purging code
2178         skinframe->loadsequence = r_skinframe.loadsequence;
2179 }
2180
2181 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2182 {
2183         if (s == NULL)
2184                 return;
2185         if (s->merged == s->base)
2186                 s->merged = NULL;
2187         R_PurgeTexture(s->stain); s->stain = NULL;
2188         R_PurgeTexture(s->merged); s->merged = NULL;
2189         R_PurgeTexture(s->base); s->base = NULL;
2190         R_PurgeTexture(s->pants); s->pants = NULL;
2191         R_PurgeTexture(s->shirt); s->shirt = NULL;
2192         R_PurgeTexture(s->nmap); s->nmap = NULL;
2193         R_PurgeTexture(s->gloss); s->gloss = NULL;
2194         R_PurgeTexture(s->glow); s->glow = NULL;
2195         R_PurgeTexture(s->fog); s->fog = NULL;
2196         R_PurgeTexture(s->reflect); s->reflect = NULL;
2197         s->loadsequence = 0;
2198 }
2199
2200 void R_SkinFrame_Purge(void)
2201 {
2202         int i;
2203         skinframe_t *s;
2204         for (i = 0;i < SKINFRAME_HASH;i++)
2205         {
2206                 for (s = r_skinframe.hash[i];s;s = s->next)
2207                 {
2208                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2209                                 R_SkinFrame_PurgeSkinFrame(s);
2210                 }
2211         }
2212 }
2213
2214 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2215         skinframe_t *item;
2216         char basename[MAX_QPATH];
2217
2218         Image_StripImageExtension(name, basename, sizeof(basename));
2219
2220         if( last == NULL ) {
2221                 int hashindex;
2222                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2223                 item = r_skinframe.hash[hashindex];
2224         } else {
2225                 item = last->next;
2226         }
2227
2228         // linearly search through the hash bucket
2229         for( ; item ; item = item->next ) {
2230                 if( !strcmp( item->basename, basename ) ) {
2231                         return item;
2232                 }
2233         }
2234         return NULL;
2235 }
2236
2237 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2238 {
2239         skinframe_t *item;
2240         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2241         int hashindex;
2242         char basename[MAX_QPATH];
2243
2244         Image_StripImageExtension(name, basename, sizeof(basename));
2245
2246         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2247         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2248                 if (!strcmp(item->basename, basename) &&
2249                         item->textureflags == compareflags &&
2250                         item->comparewidth == comparewidth &&
2251                         item->compareheight == compareheight &&
2252                         item->comparecrc == comparecrc)
2253                         break;
2254
2255         if (!item)
2256         {
2257                 if (!add)
2258                         return NULL;
2259                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2260                 memset(item, 0, sizeof(*item));
2261                 strlcpy(item->basename, basename, sizeof(item->basename));
2262                 item->textureflags = compareflags;
2263                 item->comparewidth = comparewidth;
2264                 item->compareheight = compareheight;
2265                 item->comparecrc = comparecrc;
2266                 item->next = r_skinframe.hash[hashindex];
2267                 r_skinframe.hash[hashindex] = item;
2268         }
2269         else if (textureflags & TEXF_FORCE_RELOAD)
2270                 R_SkinFrame_PurgeSkinFrame(item);
2271
2272         R_SkinFrame_MarkUsed(item);
2273         return item;
2274 }
2275
2276 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2277         { \
2278                 unsigned long long avgcolor[5], wsum; \
2279                 int pix, comp, w; \
2280                 avgcolor[0] = 0; \
2281                 avgcolor[1] = 0; \
2282                 avgcolor[2] = 0; \
2283                 avgcolor[3] = 0; \
2284                 avgcolor[4] = 0; \
2285                 wsum = 0; \
2286                 for(pix = 0; pix < cnt; ++pix) \
2287                 { \
2288                         w = 0; \
2289                         for(comp = 0; comp < 3; ++comp) \
2290                                 w += getpixel; \
2291                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2292                         { \
2293                                 ++wsum; \
2294                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2295                                 w = getpixel; \
2296                                 for(comp = 0; comp < 3; ++comp) \
2297                                         avgcolor[comp] += getpixel * w; \
2298                                 avgcolor[3] += w; \
2299                         } \
2300                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2301                         avgcolor[4] += getpixel; \
2302                 } \
2303                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2304                         avgcolor[3] = 1; \
2305                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2306                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2307                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2308                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2309         }
2310
2311 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2312 {
2313         skinframe_t *skinframe;
2314
2315         if (cls.state == ca_dedicated)
2316                 return NULL;
2317
2318         // return an existing skinframe if already loaded
2319         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2320         if (skinframe && skinframe->base)
2321                 return skinframe;
2322
2323         // if the skinframe doesn't exist this will create it
2324         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2325 }
2326
2327 extern cvar_t gl_picmip;
2328 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2329 {
2330         int j;
2331         unsigned char *pixels;
2332         unsigned char *bumppixels;
2333         unsigned char *basepixels = NULL;
2334         int basepixels_width = 0;
2335         int basepixels_height = 0;
2336         rtexture_t *ddsbase = NULL;
2337         qbool ddshasalpha = false;
2338         float ddsavgcolor[4];
2339         char basename[MAX_QPATH];
2340         int miplevel = R_PicmipForFlags(textureflags);
2341         int savemiplevel = miplevel;
2342         int mymiplevel;
2343         char vabuf[1024];
2344
2345         if (cls.state == ca_dedicated)
2346                 return NULL;
2347
2348         Image_StripImageExtension(name, basename, sizeof(basename));
2349
2350         // check for DDS texture file first
2351         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2352         {
2353                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2354                 if (basepixels == NULL && fallbacknotexture)
2355                         basepixels = Image_GenerateNoTexture();
2356                 if (basepixels == NULL)
2357                         return NULL;
2358         }
2359
2360         // FIXME handle miplevel
2361
2362         if (developer_loading.integer)
2363                 Con_Printf("loading skin \"%s\"\n", name);
2364
2365         // we've got some pixels to store, so really allocate this new texture now
2366         if (!skinframe)
2367                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2368         textureflags &= ~TEXF_FORCE_RELOAD;
2369         skinframe->stain = NULL;
2370         skinframe->merged = NULL;
2371         skinframe->base = NULL;
2372         skinframe->pants = NULL;
2373         skinframe->shirt = NULL;
2374         skinframe->nmap = NULL;
2375         skinframe->gloss = NULL;
2376         skinframe->glow = NULL;
2377         skinframe->fog = NULL;
2378         skinframe->reflect = NULL;
2379         skinframe->hasalpha = false;
2380         // we could store the q2animname here too
2381
2382         if (ddsbase)
2383         {
2384                 skinframe->base = ddsbase;
2385                 skinframe->hasalpha = ddshasalpha;
2386                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2387                 if (r_loadfog && skinframe->hasalpha)
2388                         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);
2389                 //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]);
2390         }
2391         else
2392         {
2393                 basepixels_width = image_width;
2394                 basepixels_height = image_height;
2395                 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);
2396                 if (textureflags & TEXF_ALPHA)
2397                 {
2398                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2399                         {
2400                                 if (basepixels[j] < 255)
2401                                 {
2402                                         skinframe->hasalpha = true;
2403                                         break;
2404                                 }
2405                         }
2406                         if (r_loadfog && skinframe->hasalpha)
2407                         {
2408                                 // has transparent pixels
2409                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2410                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2411                                 {
2412                                         pixels[j+0] = 255;
2413                                         pixels[j+1] = 255;
2414                                         pixels[j+2] = 255;
2415                                         pixels[j+3] = basepixels[j+3];
2416                                 }
2417                                 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);
2418                                 Mem_Free(pixels);
2419                         }
2420                 }
2421                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2422 #ifndef USE_GLES2
2423                 //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]);
2424                 if (r_savedds && skinframe->base)
2425                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2426                 if (r_savedds && skinframe->fog)
2427                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2428 #endif
2429         }
2430
2431         if (r_loaddds)
2432         {
2433                 mymiplevel = savemiplevel;
2434                 if (r_loadnormalmap)
2435                         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);
2436                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2437                 if (r_loadgloss)
2438                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2439                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2440                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2441                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2442         }
2443
2444         // _norm is the name used by tenebrae and has been adopted as standard
2445         if (r_loadnormalmap && skinframe->nmap == NULL)
2446         {
2447                 mymiplevel = savemiplevel;
2448                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2449                 {
2450                         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);
2451                         Mem_Free(pixels);
2452                         pixels = NULL;
2453                 }
2454                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2455                 {
2456                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2457                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2458                         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);
2459                         Mem_Free(pixels);
2460                         Mem_Free(bumppixels);
2461                 }
2462                 else if (r_shadow_bumpscale_basetexture.value > 0)
2463                 {
2464                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2465                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2466                         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);
2467                         Mem_Free(pixels);
2468                 }
2469 #ifndef USE_GLES2
2470                 if (r_savedds && skinframe->nmap)
2471                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2472 #endif
2473         }
2474
2475         // _luma is supported only for tenebrae compatibility
2476         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2477         // _glow is the preferred name
2478         mymiplevel = savemiplevel;
2479         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))))
2480         {
2481                 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);
2482 #ifndef USE_GLES2
2483                 if (r_savedds && skinframe->glow)
2484                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2485 #endif
2486                 Mem_Free(pixels);pixels = NULL;
2487         }
2488
2489         mymiplevel = savemiplevel;
2490         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2491         {
2492                 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);
2493 #ifndef USE_GLES2
2494                 if (r_savedds && skinframe->gloss)
2495                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2496 #endif
2497                 Mem_Free(pixels);
2498                 pixels = NULL;
2499         }
2500
2501         mymiplevel = savemiplevel;
2502         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2503         {
2504                 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);
2505 #ifndef USE_GLES2
2506                 if (r_savedds && skinframe->pants)
2507                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2508 #endif
2509                 Mem_Free(pixels);
2510                 pixels = NULL;
2511         }
2512
2513         mymiplevel = savemiplevel;
2514         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2515         {
2516                 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);
2517 #ifndef USE_GLES2
2518                 if (r_savedds && skinframe->shirt)
2519                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2520 #endif
2521                 Mem_Free(pixels);
2522                 pixels = NULL;
2523         }
2524
2525         mymiplevel = savemiplevel;
2526         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2527         {
2528                 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);
2529 #ifndef USE_GLES2
2530                 if (r_savedds && skinframe->reflect)
2531                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2532 #endif
2533                 Mem_Free(pixels);
2534                 pixels = NULL;
2535         }
2536
2537         if (basepixels)
2538                 Mem_Free(basepixels);
2539
2540         return skinframe;
2541 }
2542
2543 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qbool sRGB)
2544 {
2545         int i;
2546         skinframe_t *skinframe;
2547         char vabuf[1024];
2548
2549         if (cls.state == ca_dedicated)
2550                 return NULL;
2551
2552         // if already loaded just return it, otherwise make a new skinframe
2553         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2554         if (skinframe->base)
2555                 return skinframe;
2556         textureflags &= ~TEXF_FORCE_RELOAD;
2557
2558         skinframe->stain = NULL;
2559         skinframe->merged = NULL;
2560         skinframe->base = NULL;
2561         skinframe->pants = NULL;
2562         skinframe->shirt = NULL;
2563         skinframe->nmap = NULL;
2564         skinframe->gloss = NULL;
2565         skinframe->glow = NULL;
2566         skinframe->fog = NULL;
2567         skinframe->reflect = NULL;
2568         skinframe->hasalpha = false;
2569
2570         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2571         if (!skindata)
2572                 return NULL;
2573
2574         if (developer_loading.integer)
2575                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2576
2577         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2578         {
2579                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2580                 unsigned char *b = a + width * height * 4;
2581                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2582                 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);
2583                 Mem_Free(a);
2584         }
2585         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2586         if (textureflags & TEXF_ALPHA)
2587         {
2588                 for (i = 3;i < width * height * 4;i += 4)
2589                 {
2590                         if (skindata[i] < 255)
2591                         {
2592                                 skinframe->hasalpha = true;
2593                                 break;
2594                         }
2595                 }
2596                 if (r_loadfog && skinframe->hasalpha)
2597                 {
2598                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2599                         memcpy(fogpixels, skindata, width * height * 4);
2600                         for (i = 0;i < width * height * 4;i += 4)
2601                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2602                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2603                         Mem_Free(fogpixels);
2604                 }
2605         }
2606
2607         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2608         //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]);
2609
2610         return skinframe;
2611 }
2612
2613 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2614 {
2615         int i;
2616         int featuresmask;
2617         skinframe_t *skinframe;
2618
2619         if (cls.state == ca_dedicated)
2620                 return NULL;
2621
2622         // if already loaded just return it, otherwise make a new skinframe
2623         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2624         if (skinframe->base)
2625                 return skinframe;
2626         //textureflags &= ~TEXF_FORCE_RELOAD;
2627
2628         skinframe->stain = NULL;
2629         skinframe->merged = NULL;
2630         skinframe->base = NULL;
2631         skinframe->pants = NULL;
2632         skinframe->shirt = NULL;
2633         skinframe->nmap = NULL;
2634         skinframe->gloss = NULL;
2635         skinframe->glow = NULL;
2636         skinframe->fog = NULL;
2637         skinframe->reflect = NULL;
2638         skinframe->hasalpha = false;
2639
2640         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2641         if (!skindata)
2642                 return NULL;
2643
2644         if (developer_loading.integer)
2645                 Con_Printf("loading quake skin \"%s\"\n", name);
2646
2647         // 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)
2648         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2649         memcpy(skinframe->qpixels, skindata, width*height);
2650         skinframe->qwidth = width;
2651         skinframe->qheight = height;
2652
2653         featuresmask = 0;
2654         for (i = 0;i < width * height;i++)
2655                 featuresmask |= palette_featureflags[skindata[i]];
2656
2657         skinframe->hasalpha = false;
2658         // fence textures
2659         if (name[0] == '{')
2660                 skinframe->hasalpha = true;
2661         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2662         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2663         skinframe->qgeneratemerged = true;
2664         skinframe->qgeneratebase = skinframe->qhascolormapping;
2665         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2666
2667         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2668         //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]);
2669
2670         return skinframe;
2671 }
2672
2673 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2674 {
2675         int width;
2676         int height;
2677         unsigned char *skindata;
2678         char vabuf[1024];
2679
2680         if (!skinframe->qpixels)
2681                 return;
2682
2683         if (!skinframe->qhascolormapping)
2684                 colormapped = false;
2685
2686         if (colormapped)
2687         {
2688                 if (!skinframe->qgeneratebase)
2689                         return;
2690         }
2691         else
2692         {
2693                 if (!skinframe->qgeneratemerged)
2694                         return;
2695         }
2696
2697         width = skinframe->qwidth;
2698         height = skinframe->qheight;
2699         skindata = skinframe->qpixels;
2700
2701         if (skinframe->qgeneratenmap)
2702         {
2703                 unsigned char *a, *b;
2704                 skinframe->qgeneratenmap = false;
2705                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2706                 b = a + width * height * 4;
2707                 // use either a custom palette or the quake palette
2708                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2709                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2710                 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);
2711                 Mem_Free(a);
2712         }
2713
2714         if (skinframe->qgenerateglow)
2715         {
2716                 skinframe->qgenerateglow = false;
2717                 if (skinframe->hasalpha) // fence textures
2718                         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
2719                 else
2720                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2721         }
2722
2723         if (colormapped)
2724         {
2725                 skinframe->qgeneratebase = false;
2726                 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);
2727                 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);
2728                 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);
2729         }
2730         else
2731         {
2732                 skinframe->qgeneratemerged = false;
2733                 if (skinframe->hasalpha) // fence textures
2734                         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);
2735                 else
2736                         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);
2737         }
2738
2739         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2740         {
2741                 Mem_Free(skinframe->qpixels);
2742                 skinframe->qpixels = NULL;
2743         }
2744 }
2745
2746 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)
2747 {
2748         int i;
2749         skinframe_t *skinframe;
2750         char vabuf[1024];
2751
2752         if (cls.state == ca_dedicated)
2753                 return NULL;
2754
2755         // if already loaded just return it, otherwise make a new skinframe
2756         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2757         if (skinframe->base)
2758                 return skinframe;
2759         textureflags &= ~TEXF_FORCE_RELOAD;
2760
2761         skinframe->stain = NULL;
2762         skinframe->merged = NULL;
2763         skinframe->base = NULL;
2764         skinframe->pants = NULL;
2765         skinframe->shirt = NULL;
2766         skinframe->nmap = NULL;
2767         skinframe->gloss = NULL;
2768         skinframe->glow = NULL;
2769         skinframe->fog = NULL;
2770         skinframe->reflect = NULL;
2771         skinframe->hasalpha = false;
2772
2773         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2774         if (!skindata)
2775                 return NULL;
2776
2777         if (developer_loading.integer)
2778                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2779
2780         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2781         if ((textureflags & TEXF_ALPHA) && alphapalette)
2782         {
2783                 for (i = 0;i < width * height;i++)
2784                 {
2785                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2786                         {
2787                                 skinframe->hasalpha = true;
2788                                 break;
2789                         }
2790                 }
2791                 if (r_loadfog && skinframe->hasalpha)
2792                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2793         }
2794
2795         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2796         //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]);
2797
2798         return skinframe;
2799 }
2800
2801 skinframe_t *R_SkinFrame_LoadMissing(void)
2802 {
2803         skinframe_t *skinframe;
2804
2805         if (cls.state == ca_dedicated)
2806                 return NULL;
2807
2808         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2809         skinframe->stain = NULL;
2810         skinframe->merged = NULL;
2811         skinframe->base = NULL;
2812         skinframe->pants = NULL;
2813         skinframe->shirt = NULL;
2814         skinframe->nmap = NULL;
2815         skinframe->gloss = NULL;
2816         skinframe->glow = NULL;
2817         skinframe->fog = NULL;
2818         skinframe->reflect = NULL;
2819         skinframe->hasalpha = false;
2820
2821         skinframe->avgcolor[0] = rand() / RAND_MAX;
2822         skinframe->avgcolor[1] = rand() / RAND_MAX;
2823         skinframe->avgcolor[2] = rand() / RAND_MAX;
2824         skinframe->avgcolor[3] = 1;
2825
2826         return skinframe;
2827 }
2828
2829 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2830 {
2831         if (cls.state == ca_dedicated)
2832                 return NULL;
2833
2834         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2835 }
2836
2837 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2838 {
2839         skinframe_t *skinframe;
2840         if (cls.state == ca_dedicated)
2841                 return NULL;
2842         // if already loaded just return it, otherwise make a new skinframe
2843         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2844         if (skinframe->base)
2845                 return skinframe;
2846         textureflags &= ~TEXF_FORCE_RELOAD;
2847         skinframe->stain = NULL;
2848         skinframe->merged = NULL;
2849         skinframe->base = NULL;
2850         skinframe->pants = NULL;
2851         skinframe->shirt = NULL;
2852         skinframe->nmap = NULL;
2853         skinframe->gloss = NULL;
2854         skinframe->glow = NULL;
2855         skinframe->fog = NULL;
2856         skinframe->reflect = NULL;
2857         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2858         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2859         if (!tex)
2860                 return NULL;
2861         if (developer_loading.integer)
2862                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2863         skinframe->base = skinframe->merged = tex;
2864         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2865         return skinframe;
2866 }
2867
2868 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2869 typedef struct suffixinfo_s
2870 {
2871         const char *suffix;
2872         qbool flipx, flipy, flipdiagonal;
2873 }
2874 suffixinfo_t;
2875 static suffixinfo_t suffix[3][6] =
2876 {
2877         {
2878                 {"px",   false, false, false},
2879                 {"nx",   false, false, false},
2880                 {"py",   false, false, false},
2881                 {"ny",   false, false, false},
2882                 {"pz",   false, false, false},
2883                 {"nz",   false, false, false}
2884         },
2885         {
2886                 {"posx", false, false, false},
2887                 {"negx", false, false, false},
2888                 {"posy", false, false, false},
2889                 {"negy", false, false, false},
2890                 {"posz", false, false, false},
2891                 {"negz", false, false, false}
2892         },
2893         {
2894                 {"rt",    true, false,  true},
2895                 {"lf",   false,  true,  true},
2896                 {"ft",    true,  true, false},
2897                 {"bk",   false, false, false},
2898                 {"up",    true, false,  true},
2899                 {"dn",    true, false,  true}
2900         }
2901 };
2902
2903 static int componentorder[4] = {0, 1, 2, 3};
2904
2905 static rtexture_t *R_LoadCubemap(const char *basename)
2906 {
2907         int i, j, cubemapsize, forcefilter;
2908         unsigned char *cubemappixels, *image_buffer;
2909         rtexture_t *cubemaptexture;
2910         char name[256];
2911
2912         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2913         forcefilter = TEXF_FORCELINEAR;
2914         if (basename && basename[0] == '!')
2915         {
2916                 basename++;
2917                 forcefilter = TEXF_FORCENEAREST;
2918         }
2919         // must start 0 so the first loadimagepixels has no requested width/height
2920         cubemapsize = 0;
2921         cubemappixels = NULL;
2922         cubemaptexture = NULL;
2923         // keep trying different suffix groups (posx, px, rt) until one loads
2924         for (j = 0;j < 3 && !cubemappixels;j++)
2925         {
2926                 // load the 6 images in the suffix group
2927                 for (i = 0;i < 6;i++)
2928                 {
2929                         // generate an image name based on the base and and suffix
2930                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2931                         // load it
2932                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2933                         {
2934                                 // an image loaded, make sure width and height are equal
2935                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2936                                 {
2937                                         // if this is the first image to load successfully, allocate the cubemap memory
2938                                         if (!cubemappixels && image_width >= 1)
2939                                         {
2940                                                 cubemapsize = image_width;
2941                                                 // note this clears to black, so unavailable sides are black
2942                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2943                                         }
2944                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2945                                         if (cubemappixels)
2946                                                 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);
2947                                 }
2948                                 else
2949                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2950                                 // free the image
2951                                 Mem_Free(image_buffer);
2952                         }
2953                 }
2954         }
2955         // if a cubemap loaded, upload it
2956         if (cubemappixels)
2957         {
2958                 if (developer_loading.integer)
2959                         Con_Printf("loading cubemap \"%s\"\n", basename);
2960
2961                 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);
2962                 Mem_Free(cubemappixels);
2963         }
2964         else
2965         {
2966                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2967                 if (developer_loading.integer)
2968                 {
2969                         Con_Printf("(tried tried images ");
2970                         for (j = 0;j < 3;j++)
2971                                 for (i = 0;i < 6;i++)
2972                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2973                         Con_Print(" and was unable to find any of them).\n");
2974                 }
2975         }
2976         return cubemaptexture;
2977 }
2978
2979 rtexture_t *R_GetCubemap(const char *basename)
2980 {
2981         int i;
2982         for (i = 0;i < r_texture_numcubemaps;i++)
2983                 if (r_texture_cubemaps[i] != NULL)
2984                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2985                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2986         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2987                 return r_texture_whitecube;
2988         r_texture_numcubemaps++;
2989         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2990         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2991         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2992         return r_texture_cubemaps[i]->texture;
2993 }
2994
2995 static void R_Main_FreeViewCache(void)
2996 {
2997         if (r_refdef.viewcache.entityvisible)
2998                 Mem_Free(r_refdef.viewcache.entityvisible);
2999         if (r_refdef.viewcache.world_pvsbits)
3000                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3001         if (r_refdef.viewcache.world_leafvisible)
3002                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3003         if (r_refdef.viewcache.world_surfacevisible)
3004                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3005         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3006 }
3007
3008 static void R_Main_ResizeViewCache(void)
3009 {
3010         int numentities = r_refdef.scene.numentities;
3011         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3012         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3013         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3014         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3015         if (r_refdef.viewcache.maxentities < numentities)
3016         {
3017                 r_refdef.viewcache.maxentities = numentities;
3018                 if (r_refdef.viewcache.entityvisible)
3019                         Mem_Free(r_refdef.viewcache.entityvisible);
3020                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3021         }
3022         if (r_refdef.viewcache.world_numclusters != numclusters)
3023         {
3024                 r_refdef.viewcache.world_numclusters = numclusters;
3025                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3026                 if (r_refdef.viewcache.world_pvsbits)
3027                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3028                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3029         }
3030         if (r_refdef.viewcache.world_numleafs != numleafs)
3031         {
3032                 r_refdef.viewcache.world_numleafs = numleafs;
3033                 if (r_refdef.viewcache.world_leafvisible)
3034                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3035                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3036         }
3037         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3038         {
3039                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3040                 if (r_refdef.viewcache.world_surfacevisible)
3041                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3042                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3043         }
3044 }
3045
3046 extern rtexture_t *loadingscreentexture;
3047 static void gl_main_start(void)
3048 {
3049         loadingscreentexture = NULL;
3050         r_texture_blanknormalmap = NULL;
3051         r_texture_white = NULL;
3052         r_texture_grey128 = NULL;
3053         r_texture_black = NULL;
3054         r_texture_whitecube = NULL;
3055         r_texture_normalizationcube = NULL;
3056         r_texture_fogattenuation = NULL;
3057         r_texture_fogheighttexture = NULL;
3058         r_texture_gammaramps = NULL;
3059         r_texture_numcubemaps = 0;
3060         r_uniformbufferalignment = 32;
3061
3062         r_loaddds = r_texture_dds_load.integer != 0;
3063         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3064
3065         switch(vid.renderpath)
3066         {
3067         case RENDERPATH_GL32:
3068         case RENDERPATH_GLES2:
3069                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3070                 Cvar_SetValueQuick(&gl_combine, 1);
3071                 Cvar_SetValueQuick(&r_glsl, 1);
3072                 r_loadnormalmap = true;
3073                 r_loadgloss = true;
3074                 r_loadfog = false;
3075 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3076                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3077 #endif
3078                 break;
3079         }
3080
3081         R_AnimCache_Free();
3082         R_FrameData_Reset();
3083         R_BufferData_Reset();
3084
3085         r_numqueries = 0;
3086         r_maxqueries = 0;
3087         memset(r_queries, 0, sizeof(r_queries));
3088
3089         r_qwskincache = NULL;
3090         r_qwskincache_size = 0;
3091
3092         // due to caching of texture_t references, the collision cache must be reset
3093         Collision_Cache_Reset(true);
3094
3095         // set up r_skinframe loading system for textures
3096         memset(&r_skinframe, 0, sizeof(r_skinframe));
3097         r_skinframe.loadsequence = 1;
3098         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3099
3100         r_main_texturepool = R_AllocTexturePool();
3101         R_BuildBlankTextures();
3102         R_BuildNoTexture();
3103         R_BuildWhiteCube();
3104 #ifndef USE_GLES2
3105         R_BuildNormalizationCube();
3106 #endif //USE_GLES2
3107         r_texture_fogattenuation = NULL;
3108         r_texture_fogheighttexture = NULL;
3109         r_texture_gammaramps = NULL;
3110         //r_texture_fogintensity = NULL;
3111         memset(&r_fb, 0, sizeof(r_fb));
3112         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3113         r_glsl_permutation = NULL;
3114         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3115         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3116         memset(&r_svbsp, 0, sizeof (r_svbsp));
3117
3118         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3119         r_texture_numcubemaps = 0;
3120
3121         r_refdef.fogmasktable_density = 0;
3122
3123 #ifdef __ANDROID__
3124         // For Steelstorm Android
3125         // FIXME CACHE the program and reload
3126         // FIXME see possible combinations for SS:BR android
3127         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3128         R_SetupShader_SetPermutationGLSL(0, 12);
3129         R_SetupShader_SetPermutationGLSL(0, 13);
3130         R_SetupShader_SetPermutationGLSL(0, 8388621);
3131         R_SetupShader_SetPermutationGLSL(3, 0);
3132         R_SetupShader_SetPermutationGLSL(3, 2048);
3133         R_SetupShader_SetPermutationGLSL(5, 0);
3134         R_SetupShader_SetPermutationGLSL(5, 2);
3135         R_SetupShader_SetPermutationGLSL(5, 2048);
3136         R_SetupShader_SetPermutationGLSL(5, 8388608);
3137         R_SetupShader_SetPermutationGLSL(11, 1);
3138         R_SetupShader_SetPermutationGLSL(11, 2049);
3139         R_SetupShader_SetPermutationGLSL(11, 8193);
3140         R_SetupShader_SetPermutationGLSL(11, 10241);
3141         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3142 #endif
3143 }
3144
3145 extern unsigned int r_shadow_occlusion_buf;
3146
3147 static void gl_main_shutdown(void)
3148 {
3149         R_RenderTarget_FreeUnused(true);
3150         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3151         R_AnimCache_Free();
3152         R_FrameData_Reset();
3153         R_BufferData_Reset();
3154
3155         R_Main_FreeViewCache();
3156
3157         switch(vid.renderpath)
3158         {
3159         case RENDERPATH_GL32:
3160         case RENDERPATH_GLES2:
3161 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3162                 if (r_maxqueries)
3163                         qglDeleteQueries(r_maxqueries, r_queries);
3164 #endif
3165                 break;
3166         }
3167         r_shadow_occlusion_buf = 0;
3168         r_numqueries = 0;
3169         r_maxqueries = 0;
3170         memset(r_queries, 0, sizeof(r_queries));
3171
3172         r_qwskincache = NULL;
3173         r_qwskincache_size = 0;
3174
3175         // clear out the r_skinframe state
3176         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3177         memset(&r_skinframe, 0, sizeof(r_skinframe));
3178
3179         if (r_svbsp.nodes)
3180                 Mem_Free(r_svbsp.nodes);
3181         memset(&r_svbsp, 0, sizeof (r_svbsp));
3182         R_FreeTexturePool(&r_main_texturepool);
3183         loadingscreentexture = NULL;
3184         r_texture_blanknormalmap = NULL;
3185         r_texture_white = NULL;
3186         r_texture_grey128 = NULL;
3187         r_texture_black = NULL;
3188         r_texture_whitecube = NULL;
3189         r_texture_normalizationcube = NULL;
3190         r_texture_fogattenuation = NULL;
3191         r_texture_fogheighttexture = NULL;
3192         r_texture_gammaramps = NULL;
3193         r_texture_numcubemaps = 0;
3194         //r_texture_fogintensity = NULL;
3195         memset(&r_fb, 0, sizeof(r_fb));
3196         R_GLSL_Restart_f(&cmd_client);
3197
3198         r_glsl_permutation = NULL;
3199         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3200         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3201 }
3202
3203 static void gl_main_newmap(void)
3204 {
3205         // FIXME: move this code to client
3206         char *entities, entname[MAX_QPATH];
3207         if (r_qwskincache)
3208                 Mem_Free(r_qwskincache);
3209         r_qwskincache = NULL;
3210         r_qwskincache_size = 0;
3211         if (cl.worldmodel)
3212         {
3213                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3214                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3215                 {
3216                         CL_ParseEntityLump(entities);
3217                         Mem_Free(entities);
3218                         return;
3219                 }
3220                 if (cl.worldmodel->brush.entities)
3221                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3222         }
3223         R_Main_FreeViewCache();
3224
3225         R_FrameData_Reset();
3226         R_BufferData_Reset();
3227 }
3228
3229 void GL_Main_Init(void)
3230 {
3231         int i;
3232         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3233         R_InitShaderModeInfo();
3234
3235         Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3236         Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3237         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3238         if (gamemode == GAME_NEHAHRA)
3239         {
3240                 Cvar_RegisterVariable (&gl_fogenable);
3241                 Cvar_RegisterVariable (&gl_fogdensity);
3242                 Cvar_RegisterVariable (&gl_fogred);
3243                 Cvar_RegisterVariable (&gl_foggreen);
3244                 Cvar_RegisterVariable (&gl_fogblue);
3245                 Cvar_RegisterVariable (&gl_fogstart);
3246                 Cvar_RegisterVariable (&gl_fogend);
3247                 Cvar_RegisterVariable (&gl_skyclip);
3248         }
3249         Cvar_RegisterVariable(&r_motionblur);
3250         Cvar_RegisterVariable(&r_damageblur);
3251         Cvar_RegisterVariable(&r_motionblur_averaging);
3252         Cvar_RegisterVariable(&r_motionblur_randomize);
3253         Cvar_RegisterVariable(&r_motionblur_minblur);
3254         Cvar_RegisterVariable(&r_motionblur_maxblur);
3255         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3256         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3257         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3258         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3259         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3260         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3261         Cvar_RegisterVariable(&r_depthfirst);
3262         Cvar_RegisterVariable(&r_useinfinitefarclip);
3263         Cvar_RegisterVariable(&r_farclip_base);
3264         Cvar_RegisterVariable(&r_farclip_world);
3265         Cvar_RegisterVariable(&r_nearclip);
3266         Cvar_RegisterVariable(&r_deformvertexes);
3267         Cvar_RegisterVariable(&r_transparent);
3268         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3269         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3270         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3271         Cvar_RegisterVariable(&r_showoverdraw);
3272         Cvar_RegisterVariable(&r_showbboxes);
3273         Cvar_RegisterVariable(&r_showbboxes_client);
3274         Cvar_RegisterVariable(&r_showsurfaces);
3275         Cvar_RegisterVariable(&r_showtris);
3276         Cvar_RegisterVariable(&r_shownormals);
3277         Cvar_RegisterVariable(&r_showlighting);
3278         Cvar_RegisterVariable(&r_showcollisionbrushes);
3279         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3280         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3281         Cvar_RegisterVariable(&r_showdisabledepthtest);
3282         Cvar_RegisterVariable(&r_showspriteedges);
3283         Cvar_RegisterVariable(&r_showparticleedges);
3284         Cvar_RegisterVariable(&r_drawportals);
3285         Cvar_RegisterVariable(&r_drawentities);
3286         Cvar_RegisterVariable(&r_draw2d);
3287         Cvar_RegisterVariable(&r_drawworld);
3288         Cvar_RegisterVariable(&r_cullentities_trace);
3289         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3290         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3291         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3292         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3293         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3294         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3295         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3296         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3297         Cvar_RegisterVariable(&r_sortentities);
3298         Cvar_RegisterVariable(&r_drawviewmodel);
3299         Cvar_RegisterVariable(&r_drawexteriormodel);
3300         Cvar_RegisterVariable(&r_speeds);
3301         Cvar_RegisterVariable(&r_fullbrights);
3302         Cvar_RegisterVariable(&r_wateralpha);
3303         Cvar_RegisterVariable(&r_dynamic);
3304         Cvar_RegisterVariable(&r_fullbright_directed);
3305         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3306         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3307         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3308         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3309         Cvar_RegisterVariable(&r_fullbright);
3310         Cvar_RegisterVariable(&r_shadows);
3311         Cvar_RegisterVariable(&r_shadows_darken);
3312         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3313         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3314         Cvar_RegisterVariable(&r_shadows_throwdistance);
3315         Cvar_RegisterVariable(&r_shadows_throwdirection);
3316         Cvar_RegisterVariable(&r_shadows_focus);
3317         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3318         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3319         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3320         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3321         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3322         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3323         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3324         Cvar_RegisterVariable(&r_fog_exp2);
3325         Cvar_RegisterVariable(&r_fog_clear);
3326         Cvar_RegisterVariable(&r_drawfog);
3327         Cvar_RegisterVariable(&r_transparentdepthmasking);
3328         Cvar_RegisterVariable(&r_transparent_sortmindist);
3329         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3330         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3331         Cvar_RegisterVariable(&r_texture_dds_load);
3332         Cvar_RegisterVariable(&r_texture_dds_save);
3333         Cvar_RegisterVariable(&r_textureunits);
3334         Cvar_RegisterVariable(&gl_combine);
3335         Cvar_RegisterVariable(&r_usedepthtextures);
3336         Cvar_RegisterVariable(&r_viewfbo);
3337         Cvar_RegisterVariable(&r_rendertarget_debug);
3338         Cvar_RegisterVariable(&r_viewscale);
3339         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3340         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3341         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3342         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3343         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3344         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3345         Cvar_RegisterVariable(&r_glsl);
3346         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3347         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3348         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3349         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3350         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3351         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3352         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3353         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3354         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3355         Cvar_RegisterVariable(&r_glsl_postprocess);
3356         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3357         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3358         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3359         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3360         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3361         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3362         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3363         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3364         Cvar_RegisterVariable(&r_celshading);
3365         Cvar_RegisterVariable(&r_celoutlines);
3366
3367         Cvar_RegisterVariable(&r_water);
3368         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3369         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3370         Cvar_RegisterVariable(&r_water_clippingplanebias);
3371         Cvar_RegisterVariable(&r_water_refractdistort);
3372         Cvar_RegisterVariable(&r_water_reflectdistort);
3373         Cvar_RegisterVariable(&r_water_scissormode);
3374         Cvar_RegisterVariable(&r_water_lowquality);
3375         Cvar_RegisterVariable(&r_water_hideplayer);
3376
3377         Cvar_RegisterVariable(&r_lerpsprites);
3378         Cvar_RegisterVariable(&r_lerpmodels);
3379         Cvar_RegisterVariable(&r_nolerp_list);
3380         Cvar_RegisterVariable(&r_lerplightstyles);
3381         Cvar_RegisterVariable(&r_waterscroll);
3382         Cvar_RegisterVariable(&r_bloom);
3383         Cvar_RegisterVariable(&r_colorfringe);
3384         Cvar_RegisterVariable(&r_bloom_colorscale);
3385         Cvar_RegisterVariable(&r_bloom_brighten);
3386         Cvar_RegisterVariable(&r_bloom_blur);
3387         Cvar_RegisterVariable(&r_bloom_resolution);
3388         Cvar_RegisterVariable(&r_bloom_colorexponent);
3389         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3390         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3391         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3392         Cvar_RegisterVariable(&r_hdr_glowintensity);
3393         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3394         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3395         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3396         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3397         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3398         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3399         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3400         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3401         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3402         Cvar_RegisterVariable(&developer_texturelogging);
3403         Cvar_RegisterVariable(&gl_lightmaps);
3404         Cvar_RegisterVariable(&r_test);
3405         Cvar_RegisterVariable(&r_batch_multidraw);
3406         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3407         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3408         Cvar_RegisterVariable(&r_glsl_skeletal);
3409         Cvar_RegisterVariable(&r_glsl_saturation);
3410         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3411         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3412         Cvar_RegisterVariable(&r_framedatasize);
3413         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3414                 Cvar_RegisterVariable(&r_buffermegs[i]);
3415         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3416         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3417         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3418         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3419         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3420                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3421 #ifdef DP_MOBILETOUCH
3422         // GLES devices have terrible depth precision in general, so...
3423         Cvar_SetValueQuick(&r_nearclip, 4);
3424         Cvar_SetValueQuick(&r_farclip_base, 4096);
3425         Cvar_SetValueQuick(&r_farclip_world, 0);
3426         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3427 #endif
3428         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3429 }
3430
3431 void Render_Init(void)
3432 {
3433         gl_backend_init();
3434         R_Textures_Init();
3435         GL_Main_Init();
3436         Font_Init();
3437         GL_Draw_Init();
3438         R_Shadow_Init();
3439         R_Sky_Init();
3440         GL_Surf_Init();
3441         Sbar_Init();
3442         R_Particles_Init();
3443         R_Explosion_Init();
3444         R_LightningBeams_Init();
3445         Mod_RenderInit();
3446 }
3447
3448 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3449 {
3450         int i;
3451         mplane_t *p;
3452         if (r_trippy.integer)
3453                 return false;
3454         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3455         {
3456                 p = r_refdef.view.frustum + i;
3457                 switch(p->signbits)
3458                 {
3459                 default:
3460                 case 0:
3461                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3462                                 return true;
3463                         break;
3464                 case 1:
3465                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3466                                 return true;
3467                         break;
3468                 case 2:
3469                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3470                                 return true;
3471                         break;
3472                 case 3:
3473                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3474                                 return true;
3475                         break;
3476                 case 4:
3477                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3478                                 return true;
3479                         break;
3480                 case 5:
3481                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3482                                 return true;
3483                         break;
3484                 case 6:
3485                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3486                                 return true;
3487                         break;
3488                 case 7:
3489                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3490                                 return true;
3491                         break;
3492                 }
3493         }
3494         return false;
3495 }
3496
3497 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3498 {
3499         int i;
3500         const mplane_t *p;
3501         if (r_trippy.integer)
3502                 return false;
3503         for (i = 0;i < numplanes;i++)
3504         {
3505                 p = planes + i;
3506                 switch(p->signbits)
3507                 {
3508                 default:
3509                 case 0:
3510                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3511                                 return true;
3512                         break;
3513                 case 1:
3514                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3515                                 return true;
3516                         break;
3517                 case 2:
3518                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3519                                 return true;
3520                         break;
3521                 case 3:
3522                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3523                                 return true;
3524                         break;
3525                 case 4:
3526                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3527                                 return true;
3528                         break;
3529                 case 5:
3530                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3531                                 return true;
3532                         break;
3533                 case 6:
3534                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3535                                 return true;
3536                         break;
3537                 case 7:
3538                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3539                                 return true;
3540                         break;
3541                 }
3542         }
3543         return false;
3544 }
3545
3546 //==================================================================================
3547
3548 // LadyHavoc: this stores temporary data used within the same frame
3549
3550 typedef struct r_framedata_mem_s
3551 {
3552         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3553         size_t size; // how much usable space
3554         size_t current; // how much space in use
3555         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3556         size_t wantedsize; // how much space was allocated
3557         unsigned char *data; // start of real data (16byte aligned)
3558 }
3559 r_framedata_mem_t;
3560
3561 static r_framedata_mem_t *r_framedata_mem;
3562
3563 void R_FrameData_Reset(void)
3564 {
3565         while (r_framedata_mem)
3566         {
3567                 r_framedata_mem_t *next = r_framedata_mem->purge;
3568                 Mem_Free(r_framedata_mem);
3569                 r_framedata_mem = next;
3570         }
3571 }
3572
3573 static void R_FrameData_Resize(qbool mustgrow)
3574 {
3575         size_t wantedsize;
3576         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3577         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3578         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3579         {
3580                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3581                 newmem->wantedsize = wantedsize;
3582                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3583                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3584                 newmem->current = 0;
3585                 newmem->mark = 0;
3586                 newmem->purge = r_framedata_mem;
3587                 r_framedata_mem = newmem;
3588         }
3589 }
3590
3591 void R_FrameData_NewFrame(void)
3592 {
3593         R_FrameData_Resize(false);
3594         if (!r_framedata_mem)
3595                 return;
3596         // if we ran out of space on the last frame, free the old memory now
3597         while (r_framedata_mem->purge)
3598         {
3599                 // repeatedly remove the second item in the list, leaving only head
3600                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3601                 Mem_Free(r_framedata_mem->purge);
3602                 r_framedata_mem->purge = next;
3603         }
3604         // reset the current mem pointer
3605         r_framedata_mem->current = 0;
3606         r_framedata_mem->mark = 0;
3607 }
3608
3609 void *R_FrameData_Alloc(size_t size)
3610 {
3611         void *data;
3612         float newvalue;
3613
3614         // align to 16 byte boundary - the data pointer is already aligned, so we
3615         // only need to ensure the size of every allocation is also aligned
3616         size = (size + 15) & ~15;
3617
3618         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3619         {
3620                 // emergency - we ran out of space, allocate more memory
3621                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3622                 newvalue = r_framedatasize.value * 2.0f;
3623                 // 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
3624                 if (sizeof(size_t) >= 8)
3625                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3626                 else
3627                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3628                 // this might not be a growing it, but we'll allocate another buffer every time
3629                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3630                 R_FrameData_Resize(true);
3631         }
3632
3633         data = r_framedata_mem->data + r_framedata_mem->current;
3634         r_framedata_mem->current += size;
3635
3636         // count the usage for stats
3637         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3638         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3639
3640         return (void *)data;
3641 }
3642
3643 void *R_FrameData_Store(size_t size, void *data)
3644 {
3645         void *d = R_FrameData_Alloc(size);
3646         if (d && data)
3647                 memcpy(d, data, size);
3648         return d;
3649 }
3650
3651 void R_FrameData_SetMark(void)
3652 {
3653         if (!r_framedata_mem)
3654                 return;
3655         r_framedata_mem->mark = r_framedata_mem->current;
3656 }
3657
3658 void R_FrameData_ReturnToMark(void)
3659 {
3660         if (!r_framedata_mem)
3661                 return;
3662         r_framedata_mem->current = r_framedata_mem->mark;
3663 }
3664
3665 //==================================================================================
3666
3667 // avoid reusing the same buffer objects on consecutive frames
3668 #define R_BUFFERDATA_CYCLE 3
3669
3670 typedef struct r_bufferdata_buffer_s
3671 {
3672         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3673         size_t size; // how much usable space
3674         size_t current; // how much space in use
3675         r_meshbuffer_t *buffer; // the buffer itself
3676 }
3677 r_bufferdata_buffer_t;
3678
3679 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3680 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3681
3682 /// frees all dynamic buffers
3683 void R_BufferData_Reset(void)
3684 {
3685         int cycle, type;
3686         r_bufferdata_buffer_t **p, *mem;
3687         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3688         {
3689                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3690                 {
3691                         // free all buffers
3692                         p = &r_bufferdata_buffer[cycle][type];
3693                         while (*p)
3694                         {
3695                                 mem = *p;
3696                                 *p = (*p)->purge;
3697                                 if (mem->buffer)
3698                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3699                                 Mem_Free(mem);
3700                         }
3701                 }
3702         }
3703 }
3704
3705 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3706 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3707 {
3708         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3709         size_t size;
3710         float newvalue = r_buffermegs[type].value;
3711
3712         // increase the cvar if we have to (but only if we already have a mem)
3713         if (mustgrow && mem)
3714                 newvalue *= 2.0f;
3715         newvalue = bound(0.25f, newvalue, 256.0f);
3716         while (newvalue * 1024*1024 < minsize)
3717                 newvalue *= 2.0f;
3718
3719         // clamp the cvar to valid range
3720         newvalue = bound(0.25f, newvalue, 256.0f);
3721         if (r_buffermegs[type].value != newvalue)
3722                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3723
3724         // calculate size in bytes
3725         size = (size_t)(newvalue * 1024*1024);
3726         size = bound(131072, size, 256*1024*1024);
3727
3728         // allocate a new buffer if the size is different (purge old one later)
3729         // or if we were told we must grow the buffer
3730         if (!mem || mem->size != size || mustgrow)
3731         {
3732                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3733                 mem->size = size;
3734                 mem->current = 0;
3735                 if (type == R_BUFFERDATA_VERTEX)
3736                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3737                 else if (type == R_BUFFERDATA_INDEX16)
3738                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3739                 else if (type == R_BUFFERDATA_INDEX32)
3740                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3741                 else if (type == R_BUFFERDATA_UNIFORM)
3742                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3743                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3744                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3745         }
3746 }
3747
3748 void R_BufferData_NewFrame(void)
3749 {
3750         int type;
3751         r_bufferdata_buffer_t **p, *mem;
3752         // cycle to the next frame's buffers
3753         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3754         // if we ran out of space on the last time we used these buffers, free the old memory now
3755         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3756         {
3757                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3758                 {
3759                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3760                         // free all but the head buffer, this is how we recycle obsolete
3761                         // buffers after they are no longer in use
3762                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3763                         while (*p)
3764                         {
3765                                 mem = *p;
3766                                 *p = (*p)->purge;
3767                                 if (mem->buffer)
3768                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3769                                 Mem_Free(mem);
3770                         }
3771                         // reset the current offset
3772                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3773                 }
3774         }
3775 }
3776
3777 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3778 {
3779         r_bufferdata_buffer_t *mem;
3780         int offset = 0;
3781         int padsize;
3782
3783         *returnbufferoffset = 0;
3784
3785         // align size to a byte boundary appropriate for the buffer type, this
3786         // makes all allocations have aligned start offsets
3787         if (type == R_BUFFERDATA_UNIFORM)
3788                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3789         else
3790                 padsize = (datasize + 15) & ~15;
3791
3792         // if we ran out of space in this buffer we must allocate a new one
3793         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)
3794                 R_BufferData_Resize(type, true, padsize);
3795
3796         // if the resize did not give us enough memory, fail
3797         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)
3798                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3799
3800         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3801         offset = (int)mem->current;
3802         mem->current += padsize;
3803
3804         // upload the data to the buffer at the chosen offset
3805         if (offset == 0)
3806                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3807         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3808
3809         // count the usage for stats
3810         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3811         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3812
3813         // return the buffer offset
3814         *returnbufferoffset = offset;
3815
3816         return mem->buffer;
3817 }
3818
3819 //==================================================================================
3820
3821 // LadyHavoc: animcache originally written by Echon, rewritten since then
3822
3823 /**
3824  * Animation cache prevents re-generating mesh data for an animated model
3825  * multiple times in one frame for lighting, shadowing, reflections, etc.
3826  */
3827
3828 void R_AnimCache_Free(void)
3829 {
3830 }
3831
3832 void R_AnimCache_ClearCache(void)
3833 {
3834         int i;
3835         entity_render_t *ent;
3836
3837         for (i = 0;i < r_refdef.scene.numentities;i++)
3838         {
3839                 ent = r_refdef.scene.entities[i];
3840                 ent->animcache_vertex3f = NULL;
3841                 ent->animcache_vertex3f_vertexbuffer = NULL;
3842                 ent->animcache_vertex3f_bufferoffset = 0;
3843                 ent->animcache_normal3f = NULL;
3844                 ent->animcache_normal3f_vertexbuffer = NULL;
3845                 ent->animcache_normal3f_bufferoffset = 0;
3846                 ent->animcache_svector3f = NULL;
3847                 ent->animcache_svector3f_vertexbuffer = NULL;
3848                 ent->animcache_svector3f_bufferoffset = 0;
3849                 ent->animcache_tvector3f = NULL;
3850                 ent->animcache_tvector3f_vertexbuffer = NULL;
3851                 ent->animcache_tvector3f_bufferoffset = 0;
3852                 ent->animcache_skeletaltransform3x4 = NULL;
3853                 ent->animcache_skeletaltransform3x4buffer = NULL;
3854                 ent->animcache_skeletaltransform3x4offset = 0;
3855                 ent->animcache_skeletaltransform3x4size = 0;
3856         }
3857 }
3858
3859 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3860 {
3861         model_t *model = ent->model;
3862         int numvertices;
3863
3864         // see if this ent is worth caching
3865         if (!model || !model->Draw || !model->AnimateVertices)
3866                 return false;
3867         // nothing to cache if it contains no animations and has no skeleton
3868         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3869                 return false;
3870         // see if it is already cached for gpuskeletal
3871         if (ent->animcache_skeletaltransform3x4)
3872                 return false;
3873         // see if it is already cached as a mesh
3874         if (ent->animcache_vertex3f)
3875         {
3876                 // check if we need to add normals or tangents
3877                 if (ent->animcache_normal3f)
3878                         wantnormals = false;
3879                 if (ent->animcache_svector3f)
3880                         wanttangents = false;
3881                 if (!wantnormals && !wanttangents)
3882                         return false;
3883         }
3884
3885         // check which kind of cache we need to generate
3886         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3887         {
3888                 // cache the skeleton so the vertex shader can use it
3889                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3890                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3891                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3892                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3893                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3894                 // note: this can fail if the buffer is at the grow limit
3895                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3896                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3897         }
3898         else if (ent->animcache_vertex3f)
3899         {
3900                 // mesh was already cached but we may need to add normals/tangents
3901                 // (this only happens with multiple views, reflections, cameras, etc)
3902                 if (wantnormals || wanttangents)
3903                 {
3904                         numvertices = model->surfmesh.num_vertices;
3905                         if (wantnormals)
3906                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3907                         if (wanttangents)
3908                         {
3909                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3910                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3911                         }
3912                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3913                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3914                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3915                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3916                 }
3917         }
3918         else
3919         {
3920                 // generate mesh cache
3921                 numvertices = model->surfmesh.num_vertices;
3922                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3923                 if (wantnormals)
3924                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3925                 if (wanttangents)
3926                 {
3927                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3928                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3929                 }
3930                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3931                 if (wantnormals || wanttangents)
3932                 {
3933                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3934                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3935                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3936                 }
3937                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3938                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3939                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3940         }
3941         return true;
3942 }
3943
3944 void R_AnimCache_CacheVisibleEntities(void)
3945 {
3946         int i;
3947
3948         // TODO: thread this
3949         // NOTE: R_PrepareRTLights() also caches entities
3950
3951         for (i = 0;i < r_refdef.scene.numentities;i++)
3952                 if (r_refdef.viewcache.entityvisible[i])
3953                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3954 }
3955
3956 //==================================================================================
3957
3958 qbool R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
3959 {
3960         long unsigned int i;
3961         int j;
3962         vec3_t eyemins, eyemaxs;
3963         vec3_t boxmins, boxmaxs;
3964         vec3_t padmins, padmaxs;
3965         vec3_t start;
3966         vec3_t end;
3967         model_t *model = r_refdef.scene.worldmodel;
3968         static vec3_t positions[] = {
3969                 { 0.5f, 0.5f, 0.5f },
3970                 { 0.0f, 0.0f, 0.0f },
3971                 { 0.0f, 0.0f, 1.0f },
3972                 { 0.0f, 1.0f, 0.0f },
3973                 { 0.0f, 1.0f, 1.0f },
3974                 { 1.0f, 0.0f, 0.0f },
3975                 { 1.0f, 0.0f, 1.0f },
3976                 { 1.0f, 1.0f, 0.0f },
3977                 { 1.0f, 1.0f, 1.0f },
3978         };
3979
3980         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3981         if (numsamples < 0)
3982                 return true;
3983
3984         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3985         if (!r_refdef.view.usevieworiginculling)
3986                 return true;
3987
3988         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3989                 return true;
3990
3991         // expand the eye box a little
3992         eyemins[0] = eye[0] - eyejitter;
3993         eyemaxs[0] = eye[0] + eyejitter;
3994         eyemins[1] = eye[1] - eyejitter;
3995         eyemaxs[1] = eye[1] + eyejitter;
3996         eyemins[2] = eye[2] - eyejitter;
3997         eyemaxs[2] = eye[2] + eyejitter;
3998         // expand the box a little
3999         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4000         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4001         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4002         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4003         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4004         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4005         // make an even larger box for the acceptable area
4006         padmins[0] = boxmins[0] - pad;
4007         padmaxs[0] = boxmaxs[0] + pad;
4008         padmins[1] = boxmins[1] - pad;
4009         padmaxs[1] = boxmaxs[1] + pad;
4010         padmins[2] = boxmins[2] - pad;
4011         padmaxs[2] = boxmaxs[2] + pad;
4012
4013         // return true if eye overlaps enlarged box
4014         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4015                 return true;
4016
4017         // try specific positions in the box first - note that these can be cached
4018         if (r_cullentities_trace_entityocclusion.integer)
4019         {
4020                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4021                 {
4022                         trace_t trace;
4023                         VectorCopy(eye, start);
4024                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4025                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4026                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4027                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4028                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4029                         // not picky - if the trace ended anywhere in the box we're good
4030                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4031                                 return true;
4032                 }
4033         }
4034         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4035                 return true;
4036
4037         // try various random positions
4038         for (j = 0; j < numsamples; j++)
4039         {
4040                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4041                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4042                 if (r_cullentities_trace_entityocclusion.integer)
4043                 {
4044                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4045                         // not picky - if the trace ended anywhere in the box we're good
4046                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4047                                 return true;
4048                 }
4049                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4050                         return true;
4051         }
4052
4053         return false;
4054 }
4055
4056
4057 static void R_View_UpdateEntityVisible (void)
4058 {
4059         int i;
4060         int renderimask;
4061         int samples;
4062         entity_render_t *ent;
4063
4064         if (r_refdef.envmap || r_fb.water.hideplayer)
4065                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4066         else if (chase_active.integer || r_fb.water.renderingscene)
4067                 renderimask = RENDER_VIEWMODEL;
4068         else
4069                 renderimask = RENDER_EXTERIORMODEL;
4070         if (!r_drawviewmodel.integer)
4071                 renderimask |= RENDER_VIEWMODEL;
4072         if (!r_drawexteriormodel.integer)
4073                 renderimask |= RENDER_EXTERIORMODEL;
4074         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4075         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4076         {
4077                 // worldmodel can check visibility
4078                 for (i = 0;i < r_refdef.scene.numentities;i++)
4079                 {
4080                         ent = r_refdef.scene.entities[i];
4081                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4082                         {
4083                                 r_refdef.viewcache.entityvisible[i] = false;
4084                                 continue;
4085                         }
4086                         if (!(ent->flags & renderimask))
4087                         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)))
4088                         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))
4089                                 r_refdef.viewcache.entityvisible[i] = true;
4090                 }
4091         }
4092         else
4093         {
4094                 // no worldmodel or it can't check visibility
4095                 for (i = 0;i < r_refdef.scene.numentities;i++)
4096                 {
4097                         ent = r_refdef.scene.entities[i];
4098                         if (!(ent->flags & renderimask))
4099                         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)))
4100                                 r_refdef.viewcache.entityvisible[i] = true;
4101                 }
4102         }
4103         if (r_cullentities_trace.integer)
4104         {
4105                 for (i = 0;i < r_refdef.scene.numentities;i++)
4106                 {
4107                         if (!r_refdef.viewcache.entityvisible[i])
4108                                 continue;
4109                         ent = r_refdef.scene.entities[i];
4110                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4111                         {
4112                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4113                                 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))
4114                                         ent->last_trace_visibility = host.realtime;
4115                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4116                                         r_refdef.viewcache.entityvisible[i] = 0;
4117                         }
4118                 }
4119         }
4120 }
4121
4122 /// only used if skyrendermasked, and normally returns false
4123 static int R_DrawBrushModelsSky (void)
4124 {
4125         int i, sky;
4126         entity_render_t *ent;
4127
4128         sky = false;
4129         for (i = 0;i < r_refdef.scene.numentities;i++)
4130         {
4131                 if (!r_refdef.viewcache.entityvisible[i])
4132                         continue;
4133                 ent = r_refdef.scene.entities[i];
4134                 if (!ent->model || !ent->model->DrawSky)
4135                         continue;
4136                 ent->model->DrawSky(ent);
4137                 sky = true;
4138         }
4139         return sky;
4140 }
4141
4142 static void R_DrawNoModel(entity_render_t *ent);
4143 static void R_DrawModels(void)
4144 {
4145         int i;
4146         entity_render_t *ent;
4147
4148         for (i = 0;i < r_refdef.scene.numentities;i++)
4149         {
4150                 if (!r_refdef.viewcache.entityvisible[i])
4151                         continue;
4152                 ent = r_refdef.scene.entities[i];
4153                 r_refdef.stats[r_stat_entities]++;
4154
4155                 if (ent->model && ent->model->Draw != NULL)
4156                         ent->model->Draw(ent);
4157                 else
4158                         R_DrawNoModel(ent);
4159         }
4160 }
4161
4162 static void R_DrawModelsDepth(void)
4163 {
4164         int i;
4165         entity_render_t *ent;
4166
4167         for (i = 0;i < r_refdef.scene.numentities;i++)
4168         {
4169                 if (!r_refdef.viewcache.entityvisible[i])
4170                         continue;
4171                 ent = r_refdef.scene.entities[i];
4172                 if (ent->model && ent->model->DrawDepth != NULL)
4173                         ent->model->DrawDepth(ent);
4174         }
4175 }
4176
4177 static void R_DrawModelsDebug(void)
4178 {
4179         int i;
4180         entity_render_t *ent;
4181
4182         for (i = 0;i < r_refdef.scene.numentities;i++)
4183         {
4184                 if (!r_refdef.viewcache.entityvisible[i])
4185                         continue;
4186                 ent = r_refdef.scene.entities[i];
4187                 if (ent->model && ent->model->DrawDebug != NULL)
4188                         ent->model->DrawDebug(ent);
4189         }
4190 }
4191
4192 static void R_DrawModelsAddWaterPlanes(void)
4193 {
4194         int i;
4195         entity_render_t *ent;
4196
4197         for (i = 0;i < r_refdef.scene.numentities;i++)
4198         {
4199                 if (!r_refdef.viewcache.entityvisible[i])
4200                         continue;
4201                 ent = r_refdef.scene.entities[i];
4202                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4203                         ent->model->DrawAddWaterPlanes(ent);
4204         }
4205 }
4206
4207 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}};
4208
4209 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4210 {
4211         if (r_hdr_irisadaptation.integer)
4212         {
4213                 vec3_t p;
4214                 vec3_t ambient;
4215                 vec3_t diffuse;
4216                 vec3_t diffusenormal;
4217                 vec3_t forward;
4218                 vec_t brightness = 0.0f;
4219                 vec_t goal;
4220                 vec_t current;
4221                 vec_t d;
4222                 int c;
4223                 VectorCopy(r_refdef.view.forward, forward);
4224                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4225                 {
4226                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4227                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4228                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4229                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4230                         d = DotProduct(forward, diffusenormal);
4231                         brightness += VectorLength(ambient);
4232                         if (d > 0)
4233                                 brightness += d * VectorLength(diffuse);
4234                 }
4235                 brightness *= 1.0f / c;
4236                 brightness += 0.00001f; // make sure it's never zero
4237                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4238                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4239                 current = r_hdr_irisadaptation_value.value;
4240                 if (current < goal)
4241                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4242                 else if (current > goal)
4243                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4244                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4245                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4246         }
4247         else if (r_hdr_irisadaptation_value.value != 1.0f)
4248                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4249 }
4250
4251 extern cvar_t r_lockvisibility;
4252 extern cvar_t r_lockpvs;
4253
4254 static void R_View_SetFrustum(const int *scissor)
4255 {
4256         int i;
4257         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4258         vec3_t forward, left, up, origin, v;
4259         if(r_lockvisibility.integer)
4260                 return;
4261         if(scissor)
4262         {
4263                 // flipped x coordinates (because x points left here)
4264                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4265                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4266                 // non-flipped y coordinates
4267                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4268                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4269         }
4270
4271         // we can't trust r_refdef.view.forward and friends in reflected scenes
4272         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4273
4274 #if 0
4275         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4276         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4277         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4278         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4279         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4280         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4281         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4282         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4283         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4284         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4285         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4286         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4287 #endif
4288
4289 #if 0
4290         zNear = r_refdef.nearclip;
4291         nudge = 1.0 - 1.0 / (1<<23);
4292         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4293         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4294         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4295         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4296         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4297         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4298         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4299         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4300 #endif
4301
4302
4303
4304 #if 0
4305         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4306         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4307         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4308         r_refdef.view.frustum[0].dist = m[15] - m[12];
4309
4310         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4311         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4312         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4313         r_refdef.view.frustum[1].dist = m[15] + m[12];
4314
4315         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4316         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4317         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4318         r_refdef.view.frustum[2].dist = m[15] - m[13];
4319
4320         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4321         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4322         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4323         r_refdef.view.frustum[3].dist = m[15] + m[13];
4324
4325         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4326         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4327         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4328         r_refdef.view.frustum[4].dist = m[15] - m[14];
4329
4330         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4331         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4332         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4333         r_refdef.view.frustum[5].dist = m[15] + m[14];
4334 #endif
4335
4336         if (r_refdef.view.useperspective)
4337         {
4338                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4339                 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]);
4340                 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]);
4341                 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]);
4342                 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]);
4343
4344                 // then the normals from the corners relative to origin
4345                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4346                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4347                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4348                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4349
4350                 // in a NORMAL view, forward cross left == up
4351                 // in a REFLECTED view, forward cross left == down
4352                 // so our cross products above need to be adjusted for a left handed coordinate system
4353                 CrossProduct(forward, left, v);
4354                 if(DotProduct(v, up) < 0)
4355                 {
4356                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4357                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4358                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4359                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4360                 }
4361
4362                 // Leaving those out was a mistake, those were in the old code, and they
4363                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4364                 // I couldn't reproduce it after adding those normalizations. --blub
4365                 VectorNormalize(r_refdef.view.frustum[0].normal);
4366                 VectorNormalize(r_refdef.view.frustum[1].normal);
4367                 VectorNormalize(r_refdef.view.frustum[2].normal);
4368                 VectorNormalize(r_refdef.view.frustum[3].normal);
4369
4370                 // make the corners absolute
4371                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4372                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4373                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4374                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4375
4376                 // one more normal
4377                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4378
4379                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4380                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4381                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4382                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4383                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4384         }
4385         else
4386         {
4387                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4388                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4389                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4390                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4391                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4392                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4393                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4394                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4395                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4396                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4397         }
4398         r_refdef.view.numfrustumplanes = 5;
4399
4400         if (r_refdef.view.useclipplane)
4401         {
4402                 r_refdef.view.numfrustumplanes = 6;
4403                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4404         }
4405
4406         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4407                 PlaneClassify(r_refdef.view.frustum + i);
4408
4409         // LadyHavoc: note to all quake engine coders, Quake had a special case
4410         // for 90 degrees which assumed a square view (wrong), so I removed it,
4411         // Quake2 has it disabled as well.
4412
4413         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4414         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4415         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4416         //PlaneClassify(&frustum[0]);
4417
4418         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4419         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4420         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4421         //PlaneClassify(&frustum[1]);
4422
4423         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4424         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4425         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4426         //PlaneClassify(&frustum[2]);
4427
4428         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4429         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4430         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4431         //PlaneClassify(&frustum[3]);
4432
4433         // nearclip plane
4434         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4435         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4436         //PlaneClassify(&frustum[4]);
4437 }
4438
4439 static void R_View_UpdateWithScissor(const int *myscissor)
4440 {
4441         R_Main_ResizeViewCache();
4442         R_View_SetFrustum(myscissor);
4443         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4444         R_View_UpdateEntityVisible();
4445 }
4446
4447 static void R_View_Update(void)
4448 {
4449         R_Main_ResizeViewCache();
4450         R_View_SetFrustum(NULL);
4451         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4452         R_View_UpdateEntityVisible();
4453 }
4454
4455 float viewscalefpsadjusted = 1.0f;
4456
4457 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4458 {
4459         const float *customclipplane = NULL;
4460         float plane[4];
4461         int /*rtwidth,*/ rtheight;
4462         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4463         {
4464                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4465                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4466                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4467                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4468                         dist = r_refdef.view.clipplane.dist;
4469                 plane[0] = r_refdef.view.clipplane.normal[0];
4470                 plane[1] = r_refdef.view.clipplane.normal[1];
4471                 plane[2] = r_refdef.view.clipplane.normal[2];
4472                 plane[3] = -dist;
4473                 customclipplane = plane;
4474         }
4475
4476         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4477         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4478
4479         if (!r_refdef.view.useperspective)
4480                 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);
4481         else if (vid.stencil && r_useinfinitefarclip.integer)
4482                 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);
4483         else
4484                 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);
4485         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4486         R_SetViewport(&r_refdef.view.viewport);
4487 }
4488
4489 void R_EntityMatrix(const matrix4x4_t *matrix)
4490 {
4491         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4492         {
4493                 gl_modelmatrixchanged = false;
4494                 gl_modelmatrix = *matrix;
4495                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4496                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4497                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4498                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4499                 CHECKGLERROR
4500                 switch(vid.renderpath)
4501                 {
4502                 case RENDERPATH_GL32:
4503                 case RENDERPATH_GLES2:
4504                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4505                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4506                         break;
4507                 }
4508         }
4509 }
4510
4511 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4512 {
4513         r_viewport_t viewport;
4514
4515         CHECKGLERROR
4516
4517         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4518         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4519         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4520         R_SetViewport(&viewport);
4521         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4522         GL_Color(1, 1, 1, 1);
4523         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4524         GL_BlendFunc(GL_ONE, GL_ZERO);
4525         GL_ScissorTest(false);
4526         GL_DepthMask(false);
4527         GL_DepthRange(0, 1);
4528         GL_DepthTest(false);
4529         GL_DepthFunc(GL_LEQUAL);
4530         R_EntityMatrix(&identitymatrix);
4531         R_Mesh_ResetTextureState();
4532         GL_PolygonOffset(0, 0);
4533         switch(vid.renderpath)
4534         {
4535         case RENDERPATH_GL32:
4536         case RENDERPATH_GLES2:
4537                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4538                 break;
4539         }
4540         GL_CullFace(GL_NONE);
4541
4542         CHECKGLERROR
4543 }
4544
4545 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4546 {
4547         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4548 }
4549
4550 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4551 {
4552         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4553         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4554         GL_Color(1, 1, 1, 1);
4555         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4556         GL_BlendFunc(GL_ONE, GL_ZERO);
4557         GL_ScissorTest(true);
4558         GL_DepthMask(true);
4559         GL_DepthRange(0, 1);
4560         GL_DepthTest(true);
4561         GL_DepthFunc(GL_LEQUAL);
4562         R_EntityMatrix(&identitymatrix);
4563         R_Mesh_ResetTextureState();
4564         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4565         switch(vid.renderpath)
4566         {
4567         case RENDERPATH_GL32:
4568         case RENDERPATH_GLES2:
4569                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4570                 break;
4571         }
4572         GL_CullFace(r_refdef.view.cullface_back);
4573 }
4574
4575 /*
4576 ================
4577 R_RenderView_UpdateViewVectors
4578 ================
4579 */
4580 void R_RenderView_UpdateViewVectors(void)
4581 {
4582         // break apart the view matrix into vectors for various purposes
4583         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4584         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4585         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4586         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4587         // make an inverted copy of the view matrix for tracking sprites
4588         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4589 }
4590
4591 void R_RenderTarget_FreeUnused(qbool force)
4592 {
4593         unsigned int i, j, end;
4594         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4595         for (i = 0; i < end; i++)
4596         {
4597                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4598                 // free resources for rendertargets that have not been used for a while
4599                 // (note: this check is run after the frame render, so any targets used
4600                 // this frame will not be affected even at low framerates)
4601                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4602                 {
4603                         if (r->fbo)
4604                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4605                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4606                                 if (r->colortexture[j])
4607                                         R_FreeTexture(r->colortexture[j]);
4608                         if (r->depthtexture)
4609                                 R_FreeTexture(r->depthtexture);
4610                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4611                 }
4612         }
4613 }
4614
4615 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4616 {
4617         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4618         x1 = x * iw;
4619         x2 = (x + w) * iw;
4620         y1 = (th - y) * ih;
4621         y2 = (th - y - h) * ih;
4622         texcoord2f[0] = x1;
4623         texcoord2f[2] = x2;
4624         texcoord2f[4] = x2;
4625         texcoord2f[6] = x1;
4626         texcoord2f[1] = y1;
4627         texcoord2f[3] = y1;
4628         texcoord2f[5] = y2;
4629         texcoord2f[7] = y2;
4630 }
4631
4632 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qbool depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4633 {
4634         unsigned int i, j, end;
4635         r_rendertarget_t *r = NULL;
4636         char vabuf[256];
4637         // first try to reuse an existing slot if possible
4638         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4639         for (i = 0; i < end; i++)
4640         {
4641                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4642                 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)
4643                         break;
4644         }
4645         if (i == end)
4646         {
4647                 // no unused exact match found, so we have to make one in the first unused slot
4648                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4649                 r->texturewidth = texturewidth;
4650                 r->textureheight = textureheight;
4651                 r->colortextype[0] = colortextype0;
4652                 r->colortextype[1] = colortextype1;
4653                 r->colortextype[2] = colortextype2;
4654                 r->colortextype[3] = colortextype3;
4655                 r->depthtextype = depthtextype;
4656                 r->depthisrenderbuffer = depthisrenderbuffer;
4657                 for (j = 0; j < 4; j++)
4658                         if (r->colortextype[j])
4659                                 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);
4660                 if (r->depthtextype)
4661                 {
4662                         if (r->depthisrenderbuffer)
4663                                 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);
4664                         else
4665                                 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);
4666                 }
4667                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4668         }
4669         r_refdef.stats[r_stat_rendertargets_used]++;
4670         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4671         r->lastusetime = host.realtime;
4672         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4673         return r;
4674 }
4675
4676 static void R_Water_StartFrame(int viewwidth, int viewheight)
4677 {
4678         int waterwidth, waterheight;
4679
4680         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4681                 return;
4682
4683         // set waterwidth and waterheight to the water resolution that will be
4684         // used (often less than the screen resolution for faster rendering)
4685         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4686         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4687
4688         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4689                 waterwidth = waterheight = 0;
4690
4691         // set up variables that will be used in shader setup
4692         r_fb.water.waterwidth = waterwidth;
4693         r_fb.water.waterheight = waterheight;
4694         r_fb.water.texturewidth = waterwidth;
4695         r_fb.water.textureheight = waterheight;
4696         r_fb.water.camerawidth = waterwidth;
4697         r_fb.water.cameraheight = waterheight;
4698         r_fb.water.screenscale[0] = 0.5f;
4699         r_fb.water.screenscale[1] = 0.5f;
4700         r_fb.water.screencenter[0] = 0.5f;
4701         r_fb.water.screencenter[1] = 0.5f;
4702         r_fb.water.enabled = waterwidth != 0;
4703
4704         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4705         r_fb.water.numwaterplanes = 0;
4706 }
4707
4708 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4709 {
4710         int planeindex, bestplaneindex, vertexindex;
4711         vec3_t mins, maxs, normal, center, v, n;
4712         vec_t planescore, bestplanescore;
4713         mplane_t plane;
4714         r_waterstate_waterplane_t *p;
4715         texture_t *t = R_GetCurrentTexture(surface->texture);
4716
4717         rsurface.texture = t;
4718         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4719         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4720         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4721                 return;
4722         // average the vertex normals, find the surface bounds (after deformvertexes)
4723         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4724         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4725         VectorCopy(n, normal);
4726         VectorCopy(v, mins);
4727         VectorCopy(v, maxs);
4728         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4729         {
4730                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4731                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4732                 VectorAdd(normal, n, normal);
4733                 mins[0] = min(mins[0], v[0]);
4734                 mins[1] = min(mins[1], v[1]);
4735                 mins[2] = min(mins[2], v[2]);
4736                 maxs[0] = max(maxs[0], v[0]);
4737                 maxs[1] = max(maxs[1], v[1]);
4738                 maxs[2] = max(maxs[2], v[2]);
4739         }
4740         VectorNormalize(normal);
4741         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4742
4743         VectorCopy(normal, plane.normal);
4744         VectorNormalize(plane.normal);
4745         plane.dist = DotProduct(center, plane.normal);
4746         PlaneClassify(&plane);
4747         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4748         {
4749                 // skip backfaces (except if nocullface is set)
4750 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4751 //                      return;
4752                 VectorNegate(plane.normal, plane.normal);
4753                 plane.dist *= -1;
4754                 PlaneClassify(&plane);
4755         }
4756
4757
4758         // find a matching plane if there is one
4759         bestplaneindex = -1;
4760         bestplanescore = 1048576.0f;
4761         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4762         {
4763                 if(p->camera_entity == t->camera_entity)
4764                 {
4765                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4766                         if (bestplaneindex < 0 || bestplanescore > planescore)
4767                         {
4768                                 bestplaneindex = planeindex;
4769                                 bestplanescore = planescore;
4770                         }
4771                 }
4772         }
4773         planeindex = bestplaneindex;
4774
4775         // if this surface does not fit any known plane rendered this frame, add one
4776         if (planeindex < 0 || bestplanescore > 0.001f)
4777         {
4778                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4779                 {
4780                         // store the new plane
4781                         planeindex = r_fb.water.numwaterplanes++;
4782                         p = r_fb.water.waterplanes + planeindex;
4783                         p->plane = plane;
4784                         // clear materialflags and pvs
4785                         p->materialflags = 0;
4786                         p->pvsvalid = false;
4787                         p->camera_entity = t->camera_entity;
4788                         VectorCopy(mins, p->mins);
4789                         VectorCopy(maxs, p->maxs);
4790                 }
4791                 else
4792                 {
4793                         // We're totally screwed.
4794                         return;
4795                 }
4796         }
4797         else
4798         {
4799                 // merge mins/maxs when we're adding this surface to the plane
4800                 p = r_fb.water.waterplanes + planeindex;
4801                 p->mins[0] = min(p->mins[0], mins[0]);
4802                 p->mins[1] = min(p->mins[1], mins[1]);
4803                 p->mins[2] = min(p->mins[2], mins[2]);
4804                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4805                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4806                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4807         }
4808         // merge this surface's materialflags into the waterplane
4809         p->materialflags |= t->currentmaterialflags;
4810         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4811         {
4812                 // merge this surface's PVS into the waterplane
4813                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4814                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4815                 {
4816                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4817                         p->pvsvalid = true;
4818                 }
4819         }
4820 }
4821
4822 extern cvar_t r_drawparticles;
4823 extern cvar_t r_drawdecals;
4824
4825 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4826 {
4827         int myscissor[4];
4828         r_refdef_view_t originalview;
4829         r_refdef_view_t myview;
4830         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;
4831         r_waterstate_waterplane_t *p;
4832         vec3_t visorigin;
4833         r_rendertarget_t *rt;
4834
4835         originalview = r_refdef.view;
4836
4837         // lowquality hack, temporarily shut down some cvars and restore afterwards
4838         qualityreduction = r_water_lowquality.integer;
4839         if (qualityreduction > 0)
4840         {
4841                 if (qualityreduction >= 1)
4842                 {
4843                         old_r_shadows = r_shadows.integer;
4844                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4845                         old_r_dlight = r_shadow_realtime_dlight.integer;
4846                         Cvar_SetValueQuick(&r_shadows, 0);
4847                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4848                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4849                 }
4850                 if (qualityreduction >= 2)
4851                 {
4852                         old_r_dynamic = r_dynamic.integer;
4853                         old_r_particles = r_drawparticles.integer;
4854                         old_r_decals = r_drawdecals.integer;
4855                         Cvar_SetValueQuick(&r_dynamic, 0);
4856                         Cvar_SetValueQuick(&r_drawparticles, 0);
4857                         Cvar_SetValueQuick(&r_drawdecals, 0);
4858                 }
4859         }
4860
4861         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4862         {
4863                 p->rt_reflection = NULL;
4864                 p->rt_refraction = NULL;
4865                 p->rt_camera = NULL;
4866         }
4867
4868         // render views
4869         r_refdef.view = originalview;
4870         r_refdef.view.showdebug = false;
4871         r_refdef.view.width = r_fb.water.waterwidth;
4872         r_refdef.view.height = r_fb.water.waterheight;
4873         r_refdef.view.useclipplane = true;
4874         myview = r_refdef.view;
4875         r_fb.water.renderingscene = true;
4876         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4877         {
4878                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4879                         continue;
4880
4881                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4882                 {
4883                         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);
4884                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4885                                 goto error;
4886                         r_refdef.view = myview;
4887                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4888                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4889                         if(r_water_scissormode.integer)
4890                         {
4891                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4892                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4893                                 {
4894                                         p->rt_reflection = NULL;
4895                                         p->rt_refraction = NULL;
4896                                         p->rt_camera = NULL;
4897                                         continue;
4898                                 }
4899                         }
4900
4901                         r_refdef.view.clipplane = p->plane;
4902                         // reflected view origin may be in solid, so don't cull with it
4903                         r_refdef.view.usevieworiginculling = false;
4904                         // reverse the cullface settings for this render
4905                         r_refdef.view.cullface_front = GL_FRONT;
4906                         r_refdef.view.cullface_back = GL_BACK;
4907                         // combined pvs (based on what can be seen from each surface center)
4908                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4909                         {
4910                                 r_refdef.view.usecustompvs = true;
4911                                 if (p->pvsvalid)
4912                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4913                                 else
4914                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4915                         }
4916
4917                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4918                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4919                         GL_ScissorTest(false);
4920                         R_ClearScreen(r_refdef.fogenabled);
4921                         GL_ScissorTest(true);
4922                         if(r_water_scissormode.integer & 2)
4923                                 R_View_UpdateWithScissor(myscissor);
4924                         else
4925                                 R_View_Update();
4926                         R_AnimCache_CacheVisibleEntities();
4927                         if(r_water_scissormode.integer & 1)
4928                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4929                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4930
4931                         r_fb.water.hideplayer = false;
4932                         p->rt_reflection = rt;
4933                 }
4934
4935                 // render the normal view scene and copy into texture
4936                 // (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)
4937                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4938                 {
4939                         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);
4940                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4941                                 goto error;
4942                         r_refdef.view = myview;
4943                         if(r_water_scissormode.integer)
4944                         {
4945                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4946                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4947                                 {
4948                                         p->rt_reflection = NULL;
4949                                         p->rt_refraction = NULL;
4950                                         p->rt_camera = NULL;
4951                                         continue;
4952                                 }
4953                         }
4954
4955                         // combined pvs (based on what can be seen from each surface center)
4956                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4957                         {
4958                                 r_refdef.view.usecustompvs = true;
4959                                 if (p->pvsvalid)
4960                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4961                                 else
4962                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4963                         }
4964
4965                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4966
4967                         r_refdef.view.clipplane = p->plane;
4968                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4969                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4970
4971                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4972                         {
4973                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4974                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4975                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4976                                 R_RenderView_UpdateViewVectors();
4977                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4978                                 {
4979                                         r_refdef.view.usecustompvs = true;
4980                                         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);
4981                                 }
4982                         }
4983
4984                         PlaneClassify(&r_refdef.view.clipplane);
4985
4986                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4987                         GL_ScissorTest(false);
4988                         R_ClearScreen(r_refdef.fogenabled);
4989                         GL_ScissorTest(true);
4990                         if(r_water_scissormode.integer & 2)
4991                                 R_View_UpdateWithScissor(myscissor);
4992                         else
4993                                 R_View_Update();
4994                         R_AnimCache_CacheVisibleEntities();
4995                         if(r_water_scissormode.integer & 1)
4996                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4997                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4998
4999                         r_fb.water.hideplayer = false;
5000                         p->rt_refraction = rt;
5001                 }
5002                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5003                 {
5004                         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);
5005                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5006                                 goto error;
5007                         r_refdef.view = myview;
5008
5009                         r_refdef.view.clipplane = p->plane;
5010                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5011                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5012
5013                         r_refdef.view.width = r_fb.water.camerawidth;
5014                         r_refdef.view.height = r_fb.water.cameraheight;
5015                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5016                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5017                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5018                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5019
5020                         if(p->camera_entity)
5021                         {
5022                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5023                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5024                         }
5025
5026                         // note: all of the view is used for displaying... so
5027                         // there is no use in scissoring
5028
5029                         // reverse the cullface settings for this render
5030                         r_refdef.view.cullface_front = GL_FRONT;
5031                         r_refdef.view.cullface_back = GL_BACK;
5032                         // also reverse the view matrix
5033                         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
5034                         R_RenderView_UpdateViewVectors();
5035                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5036                         {
5037                                 r_refdef.view.usecustompvs = true;
5038                                 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);
5039                         }
5040                         
5041                         // camera needs no clipplane
5042                         r_refdef.view.useclipplane = false;
5043                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5044                         r_refdef.view.usevieworiginculling = false;
5045
5046                         PlaneClassify(&r_refdef.view.clipplane);
5047
5048                         r_fb.water.hideplayer = false;
5049
5050                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5051                         GL_ScissorTest(false);
5052                         R_ClearScreen(r_refdef.fogenabled);
5053                         GL_ScissorTest(true);
5054                         R_View_Update();
5055                         R_AnimCache_CacheVisibleEntities();
5056                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5057
5058                         r_fb.water.hideplayer = false;
5059                         p->rt_camera = rt;
5060                 }
5061
5062         }
5063         r_fb.water.renderingscene = false;
5064         r_refdef.view = originalview;
5065         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5066         R_View_Update();
5067         R_AnimCache_CacheVisibleEntities();
5068         goto finish;
5069 error:
5070         r_refdef.view = originalview;
5071         r_fb.water.renderingscene = false;
5072         Cvar_SetValueQuick(&r_water, 0);
5073         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5074 finish:
5075         // lowquality hack, restore cvars
5076         if (qualityreduction > 0)
5077         {
5078                 if (qualityreduction >= 1)
5079                 {
5080                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5081                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5082                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5083                 }
5084                 if (qualityreduction >= 2)
5085                 {
5086                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5087                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5088                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5089                 }
5090         }
5091 }
5092
5093 static void R_Bloom_StartFrame(void)
5094 {
5095         int screentexturewidth, screentextureheight;
5096         textype_t textype = TEXTYPE_COLORBUFFER;
5097         double scale;
5098
5099         // clear the pointers to rendertargets from last frame as they're stale
5100         r_fb.rt_screen = NULL;
5101         r_fb.rt_bloom = NULL;
5102
5103         switch (vid.renderpath)
5104         {
5105         case RENDERPATH_GL32:
5106                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5107                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5108                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5109                 break;
5110         case RENDERPATH_GLES2:
5111                 r_fb.usedepthtextures = false;
5112                 break;
5113         }
5114
5115         if (r_viewscale_fpsscaling.integer)
5116         {
5117                 double actualframetime;
5118                 double targetframetime;
5119                 double adjust;
5120                 actualframetime = r_refdef.lastdrawscreentime;
5121                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5122                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5123                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5124                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5125                 {
5126                         if (adjust > 0)
5127                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5128                         else
5129                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5130                 }
5131                 viewscalefpsadjusted += adjust;
5132                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5133         }
5134         else
5135                 viewscalefpsadjusted = 1.0f;
5136
5137         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5138         if (vid.samples)
5139                 scale *= sqrt(vid.samples); // supersampling
5140         scale = bound(0.03125f, scale, 4.0f);
5141         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5142         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5143         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5144         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5145
5146         // set bloomwidth and bloomheight to the bloom resolution that will be
5147         // used (often less than the screen resolution for faster rendering)
5148         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5149         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5150         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5151         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5152         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5153
5154         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))
5155         {
5156                 Cvar_SetValueQuick(&r_bloom, 0);
5157                 Cvar_SetValueQuick(&r_motionblur, 0);
5158                 Cvar_SetValueQuick(&r_damageblur, 0);
5159         }
5160         if (!r_bloom.integer)
5161                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5162
5163         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5164         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5165         {
5166                 if (r_fb.ghosttexture)
5167                         R_FreeTexture(r_fb.ghosttexture);
5168                 r_fb.ghosttexture = NULL;
5169
5170                 r_fb.screentexturewidth = screentexturewidth;
5171                 r_fb.screentextureheight = screentextureheight;
5172                 r_fb.textype = textype;
5173
5174                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5175                 {
5176                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5177                                 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);
5178                         r_fb.ghosttexture_valid = false;
5179                 }
5180         }
5181
5182         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5183
5184         r_refdef.view.clear = true;
5185 }
5186
5187 static void R_Bloom_MakeTexture(void)
5188 {
5189         int x, range, dir;
5190         float xoffset, yoffset, r, brighten;
5191         float colorscale = r_bloom_colorscale.value;
5192         r_viewport_t bloomviewport;
5193         r_rendertarget_t *prev, *cur;
5194         textype_t textype = r_fb.rt_screen->colortextype[0];
5195
5196         r_refdef.stats[r_stat_bloom]++;
5197
5198         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5199
5200         // scale down screen texture to the bloom texture size
5201         CHECKGLERROR
5202         prev = r_fb.rt_screen;
5203         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5204         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5205         R_SetViewport(&bloomviewport);
5206         GL_CullFace(GL_NONE);
5207         GL_DepthTest(false);
5208         GL_BlendFunc(GL_ONE, GL_ZERO);
5209         GL_Color(colorscale, colorscale, colorscale, 1);
5210         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5211         // TODO: do boxfilter scale-down in shader?
5212         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5213         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5214         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5215         // we now have a properly scaled bloom image
5216
5217         // multiply bloom image by itself as many times as desired to darken it
5218         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5219         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5220         {
5221                 prev = cur;
5222                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5223                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5224                 x *= 2;
5225                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5226                 if(x <= 2)
5227                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5228                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5229                 GL_Color(1,1,1,1); // no fix factor supported here
5230                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5231                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5232                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5233                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5234         }
5235         CHECKGLERROR
5236
5237         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5238         brighten = r_bloom_brighten.value;
5239         brighten = sqrt(brighten);
5240         if(range >= 1)
5241                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5242
5243         for (dir = 0;dir < 2;dir++)
5244         {
5245                 prev = cur;
5246                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5247                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5248                 // blend on at multiple vertical offsets to achieve a vertical blur
5249                 // TODO: do offset blends using GLSL
5250                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5251                 CHECKGLERROR
5252                 GL_BlendFunc(GL_ONE, GL_ZERO);
5253                 CHECKGLERROR
5254                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5255                 CHECKGLERROR
5256                 for (x = -range;x <= range;x++)
5257                 {
5258                         if (!dir){xoffset = 0;yoffset = x;}
5259                         else {xoffset = x;yoffset = 0;}
5260                         xoffset /= (float)prev->texturewidth;
5261                         yoffset /= (float)prev->textureheight;
5262                         // compute a texcoord array with the specified x and y offset
5263                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5264                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5265                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5266                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5267                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5268                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5269                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5270                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5271                         // this r value looks like a 'dot' particle, fading sharply to
5272                         // black at the edges
5273                         // (probably not realistic but looks good enough)
5274                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5275                         //r = brighten/(range*2+1);
5276                         r = brighten / (range * 2 + 1);
5277                         if(range >= 1)
5278                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5279                         if (r <= 0)
5280                                 continue;
5281                         CHECKGLERROR
5282                         GL_Color(r, r, r, 1);
5283                         CHECKGLERROR
5284                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5285                         CHECKGLERROR
5286                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5287                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5288                         CHECKGLERROR
5289                         GL_BlendFunc(GL_ONE, GL_ONE);
5290                         CHECKGLERROR
5291                 }
5292         }
5293
5294         // now we have the bloom image, so keep track of it
5295         r_fb.rt_bloom = cur;
5296 }
5297
5298 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5299 {
5300         uint64_t permutation;
5301         float uservecs[4][4];
5302         rtexture_t *viewtexture;
5303         rtexture_t *bloomtexture;
5304
5305         R_EntityMatrix(&identitymatrix);
5306
5307         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5308         {
5309                 // declare variables
5310                 float blur_factor, blur_mouseaccel, blur_velocity;
5311                 static float blur_average; 
5312                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5313
5314                 // set a goal for the factoring
5315                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5316                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5317                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5318                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5319                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5320                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5321
5322                 // from the goal, pick an averaged value between goal and last value
5323                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5324                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5325
5326                 // enforce minimum amount of blur 
5327                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5328
5329                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5330
5331                 // calculate values into a standard alpha
5332                 cl.motionbluralpha = 1 - exp(-
5333                                 (
5334                                         (r_motionblur.value * blur_factor / 80)
5335                                         +
5336                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5337                                 )
5338                                 /
5339                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5340                                 );
5341
5342                 // randomization for the blur value to combat persistent ghosting
5343                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5344                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5345
5346                 // apply the blur
5347                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5348                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5349                 {
5350                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5351                         GL_Color(1, 1, 1, cl.motionbluralpha);
5352                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5353                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5354                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5355                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5356                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5357                 }
5358
5359                 // updates old view angles for next pass
5360                 VectorCopy(cl.viewangles, blur_oldangles);
5361
5362                 // copy view into the ghost texture
5363                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5364                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5365                 r_fb.ghosttexture_valid = true;
5366         }
5367
5368         if (r_fb.bloomwidth)
5369         {
5370                 // make the bloom texture
5371                 R_Bloom_MakeTexture();
5372         }
5373
5374 #if _MSC_VER >= 1400
5375 #define sscanf sscanf_s
5376 #endif
5377         memset(uservecs, 0, sizeof(uservecs));
5378         if (r_glsl_postprocess_uservec1_enable.integer)
5379                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5380         if (r_glsl_postprocess_uservec2_enable.integer)
5381                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5382         if (r_glsl_postprocess_uservec3_enable.integer)
5383                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5384         if (r_glsl_postprocess_uservec4_enable.integer)
5385                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5386
5387         // render to the screen fbo
5388         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5389         GL_Color(1, 1, 1, 1);
5390         GL_BlendFunc(GL_ONE, GL_ZERO);
5391
5392         viewtexture = r_fb.rt_screen->colortexture[0];
5393         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5394
5395         if (r_rendertarget_debug.integer >= 0)
5396         {
5397                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5398                 if (rt && rt->colortexture[0])
5399                 {
5400                         viewtexture = rt->colortexture[0];
5401                         bloomtexture = NULL;
5402                 }
5403         }
5404
5405         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5406         switch(vid.renderpath)
5407         {
5408         case RENDERPATH_GL32:
5409         case RENDERPATH_GLES2:
5410                 permutation =
5411                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5412                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5413                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5414                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5415                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5416                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5417                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5418                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5419                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5420                 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]);
5421                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5422                 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]);
5423                 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]);
5424                 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]);
5425                 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]);
5426                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5427                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5428                 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);
5429                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5430                 break;
5431         }
5432         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5433         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5434 }
5435
5436 matrix4x4_t r_waterscrollmatrix;
5437
5438 void R_UpdateFog(void)
5439 {
5440         // Nehahra fog
5441         if (gamemode == GAME_NEHAHRA)
5442         {
5443                 if (gl_fogenable.integer)
5444                 {
5445                         r_refdef.oldgl_fogenable = true;
5446                         r_refdef.fog_density = gl_fogdensity.value;
5447                         r_refdef.fog_red = gl_fogred.value;
5448                         r_refdef.fog_green = gl_foggreen.value;
5449                         r_refdef.fog_blue = gl_fogblue.value;
5450                         r_refdef.fog_alpha = 1;
5451                         r_refdef.fog_start = 0;
5452                         r_refdef.fog_end = gl_skyclip.value;
5453                         r_refdef.fog_height = 1<<30;
5454                         r_refdef.fog_fadedepth = 128;
5455                 }
5456                 else if (r_refdef.oldgl_fogenable)
5457                 {
5458                         r_refdef.oldgl_fogenable = false;
5459                         r_refdef.fog_density = 0;
5460                         r_refdef.fog_red = 0;
5461                         r_refdef.fog_green = 0;
5462                         r_refdef.fog_blue = 0;
5463                         r_refdef.fog_alpha = 0;
5464                         r_refdef.fog_start = 0;
5465                         r_refdef.fog_end = 0;
5466                         r_refdef.fog_height = 1<<30;
5467                         r_refdef.fog_fadedepth = 128;
5468                 }
5469         }
5470
5471         // fog parms
5472         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5473         r_refdef.fog_start = max(0, r_refdef.fog_start);
5474         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5475
5476         if (r_refdef.fog_density && r_drawfog.integer)
5477         {
5478                 r_refdef.fogenabled = true;
5479                 // this is the point where the fog reaches 0.9986 alpha, which we
5480                 // consider a good enough cutoff point for the texture
5481                 // (0.9986 * 256 == 255.6)
5482                 if (r_fog_exp2.integer)
5483                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5484                 else
5485                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5486                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5487                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5488                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5489                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5490                         R_BuildFogHeightTexture();
5491                 // fog color was already set
5492                 // update the fog texture
5493                 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)
5494                         R_BuildFogTexture();
5495                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5496                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5497         }
5498         else
5499                 r_refdef.fogenabled = false;
5500
5501         // fog color
5502         if (r_refdef.fog_density)
5503         {
5504                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5505                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5506                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5507
5508                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5509                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5510                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5511                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5512
5513                 {
5514                         vec3_t fogvec;
5515                         VectorCopy(r_refdef.fogcolor, fogvec);
5516                         //   color.rgb *= ContrastBoost * SceneBrightness;
5517                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5518                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5519                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5520                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5521                 }
5522         }
5523 }
5524
5525 void R_UpdateVariables(void)
5526 {
5527         R_Textures_Frame();
5528
5529         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5530
5531         r_refdef.farclip = r_farclip_base.value;
5532         if (r_refdef.scene.worldmodel)
5533                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5534         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5535
5536         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5537                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5538         r_refdef.polygonfactor = 0;
5539         r_refdef.polygonoffset = 0;
5540
5541         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5542         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5543         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5544         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5545         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5546         if (r_refdef.scene.worldmodel)
5547         {
5548                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5549         }
5550         if (r_showsurfaces.integer)
5551         {
5552                 r_refdef.scene.rtworld = false;
5553                 r_refdef.scene.rtworldshadows = false;
5554                 r_refdef.scene.rtdlight = false;
5555                 r_refdef.scene.rtdlightshadows = false;
5556                 r_refdef.scene.lightmapintensity = 0;
5557         }
5558
5559         r_gpuskeletal = false;
5560         switch(vid.renderpath)
5561         {
5562         case RENDERPATH_GL32:
5563                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5564         case RENDERPATH_GLES2:
5565                 if(!vid_gammatables_trivial)
5566                 {
5567                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5568                         {
5569                                 // build GLSL gamma texture
5570 #define RAMPWIDTH 256
5571                                 unsigned short ramp[RAMPWIDTH * 3];
5572                                 unsigned char rampbgr[RAMPWIDTH][4];
5573                                 int i;
5574
5575                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5576
5577                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5578                                 for(i = 0; i < RAMPWIDTH; ++i)
5579                                 {
5580                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5581                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5582                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5583                                         rampbgr[i][3] = 0;
5584                                 }
5585                                 if (r_texture_gammaramps)
5586                                 {
5587                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5588                                 }
5589                                 else
5590                                 {
5591                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5592                                 }
5593                         }
5594                 }
5595                 else
5596                 {
5597                         // remove GLSL gamma texture
5598                 }
5599                 break;
5600         }
5601 }
5602
5603 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5604 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5605 /*
5606 ================
5607 R_SelectScene
5608 ================
5609 */
5610 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5611         if( scenetype != r_currentscenetype ) {
5612                 // store the old scenetype
5613                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5614                 r_currentscenetype = scenetype;
5615                 // move in the new scene
5616                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5617         }
5618 }
5619
5620 /*
5621 ================
5622 R_GetScenePointer
5623 ================
5624 */
5625 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5626 {
5627         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5628         if( scenetype == r_currentscenetype ) {
5629                 return &r_refdef.scene;
5630         } else {
5631                 return &r_scenes_store[ scenetype ];
5632         }
5633 }
5634
5635 static int R_SortEntities_Compare(const void *ap, const void *bp)
5636 {
5637         const entity_render_t *a = *(const entity_render_t **)ap;
5638         const entity_render_t *b = *(const entity_render_t **)bp;
5639
5640         // 1. compare model
5641         if(a->model < b->model)
5642                 return -1;
5643         if(a->model > b->model)
5644                 return +1;
5645
5646         // 2. compare skin
5647         // TODO possibly calculate the REAL skinnum here first using
5648         // skinscenes?
5649         if(a->skinnum < b->skinnum)
5650                 return -1;
5651         if(a->skinnum > b->skinnum)
5652                 return +1;
5653
5654         // everything we compared is equal
5655         return 0;
5656 }
5657 static void R_SortEntities(void)
5658 {
5659         // below or equal 2 ents, sorting never gains anything
5660         if(r_refdef.scene.numentities <= 2)
5661                 return;
5662         // sort
5663         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5664 }
5665
5666 /*
5667 ================
5668 R_RenderView
5669 ================
5670 */
5671 extern cvar_t r_shadow_bouncegrid;
5672 extern cvar_t v_isometric;
5673 extern void V_MakeViewIsometric(void);
5674 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5675 {
5676         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5677         int viewfbo = 0;
5678         rtexture_t *viewdepthtexture = NULL;
5679         rtexture_t *viewcolortexture = NULL;
5680         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5681
5682         // finish any 2D rendering that was queued
5683         DrawQ_Finish();
5684
5685         if (r_timereport_active)
5686                 R_TimeReport("start");
5687         r_textureframe++; // used only by R_GetCurrentTexture
5688         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5689
5690         if(R_CompileShader_CheckStaticParms())
5691                 R_GLSL_Restart_f(&cmd_client);
5692
5693         if (!r_drawentities.integer)
5694                 r_refdef.scene.numentities = 0;
5695         else if (r_sortentities.integer)
5696                 R_SortEntities();
5697
5698         R_AnimCache_ClearCache();
5699
5700         /* adjust for stereo display */
5701         if(R_Stereo_Active())
5702         {
5703                 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);
5704                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5705         }
5706
5707         if (r_refdef.view.isoverlay)
5708         {
5709                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5710                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5711                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5712                 R_TimeReport("depthclear");
5713
5714                 r_refdef.view.showdebug = false;
5715
5716                 r_fb.water.enabled = false;
5717                 r_fb.water.numwaterplanes = 0;
5718
5719                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5720
5721                 r_refdef.view.matrix = originalmatrix;
5722
5723                 CHECKGLERROR
5724                 return;
5725         }
5726
5727         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5728         {
5729                 r_refdef.view.matrix = originalmatrix;
5730                 return;
5731         }
5732
5733         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5734         if (v_isometric.integer && r_refdef.view.ismain)
5735                 V_MakeViewIsometric();
5736
5737         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5738
5739         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5740                 // in sRGB fallback, behave similar to true sRGB: convert this
5741                 // value from linear to sRGB
5742                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5743
5744         R_RenderView_UpdateViewVectors();
5745
5746         R_Shadow_UpdateWorldLightSelection();
5747
5748         // this will set up r_fb.rt_screen
5749         R_Bloom_StartFrame();
5750
5751         // apply bloom brightness offset
5752         if(r_fb.rt_bloom)
5753                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5754
5755         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5756         if (r_fb.rt_screen)
5757         {
5758                 viewfbo = r_fb.rt_screen->fbo;
5759                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5760                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5761                 viewx = 0;
5762                 viewy = 0;
5763                 viewwidth = r_fb.rt_screen->texturewidth;
5764                 viewheight = r_fb.rt_screen->textureheight;
5765         }
5766
5767         R_Water_StartFrame(viewwidth, viewheight);
5768
5769         CHECKGLERROR
5770         if (r_timereport_active)
5771                 R_TimeReport("viewsetup");
5772
5773         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5774
5775         // clear the whole fbo every frame - otherwise the driver will consider
5776         // it to be an inter-frame texture and stall in multi-gpu configurations
5777         if (r_fb.rt_screen)
5778                 GL_ScissorTest(false);
5779         R_ClearScreen(r_refdef.fogenabled);
5780         if (r_timereport_active)
5781                 R_TimeReport("viewclear");
5782
5783         r_refdef.view.clear = true;
5784
5785         r_refdef.view.showdebug = true;
5786
5787         R_View_Update();
5788         if (r_timereport_active)
5789                 R_TimeReport("visibility");
5790
5791         R_AnimCache_CacheVisibleEntities();
5792         if (r_timereport_active)
5793                 R_TimeReport("animcache");
5794
5795         R_Shadow_UpdateBounceGridTexture();
5796         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5797
5798         r_fb.water.numwaterplanes = 0;
5799         if (r_fb.water.enabled)
5800                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5801
5802         // for the actual view render we use scissoring a fair amount, so scissor
5803         // test needs to be on
5804         if (r_fb.rt_screen)
5805                 GL_ScissorTest(true);
5806         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5807         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5808         r_fb.water.numwaterplanes = 0;
5809
5810         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5811         GL_ScissorTest(false);
5812
5813         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5814         if (r_timereport_active)
5815                 R_TimeReport("blendview");
5816
5817         r_refdef.view.matrix = originalmatrix;
5818
5819         CHECKGLERROR
5820
5821         // go back to 2d rendering
5822         DrawQ_Start();
5823 }
5824
5825 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5826 {
5827         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5828         {
5829                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5830                 if (r_timereport_active)
5831                         R_TimeReport("waterworld");
5832         }
5833
5834         // don't let sound skip if going slow
5835         if (r_refdef.scene.extraupdate)
5836                 S_ExtraUpdate ();
5837
5838         R_DrawModelsAddWaterPlanes();
5839         if (r_timereport_active)
5840                 R_TimeReport("watermodels");
5841
5842         if (r_fb.water.numwaterplanes)
5843         {
5844                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5845                 if (r_timereport_active)
5846                         R_TimeReport("waterscenes");
5847         }
5848 }
5849
5850 extern cvar_t cl_locs_show;
5851 static void R_DrawLocs(void);
5852 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5853 static void R_DrawModelDecals(void);
5854 extern qbool r_shadow_usingdeferredprepass;
5855 extern int r_shadow_shadowmapatlas_modelshadows_size;
5856 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5857 {
5858         qbool shadowmapping = false;
5859
5860         if (r_timereport_active)
5861                 R_TimeReport("beginscene");
5862
5863         r_refdef.stats[r_stat_renders]++;
5864
5865         R_UpdateFog();
5866
5867         // don't let sound skip if going slow
5868         if (r_refdef.scene.extraupdate)
5869                 S_ExtraUpdate ();
5870
5871         R_MeshQueue_BeginScene();
5872
5873         R_SkyStartFrame();
5874
5875         Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
5876
5877         if (r_timereport_active)
5878                 R_TimeReport("skystartframe");
5879
5880         if (cl.csqc_vidvars.drawworld)
5881         {
5882                 // don't let sound skip if going slow
5883                 if (r_refdef.scene.extraupdate)
5884                         S_ExtraUpdate ();
5885
5886                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5887                 {
5888                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5889                         if (r_timereport_active)
5890                                 R_TimeReport("worldsky");
5891                 }
5892
5893                 if (R_DrawBrushModelsSky() && r_timereport_active)
5894                         R_TimeReport("bmodelsky");
5895
5896                 if (skyrendermasked && skyrenderlater)
5897                 {
5898                         // we have to force off the water clipping plane while rendering sky
5899                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5900                         R_Sky();
5901                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5902                         if (r_timereport_active)
5903                                 R_TimeReport("sky");
5904                 }
5905         }
5906
5907         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5908         r_shadow_viewfbo = viewfbo;
5909         r_shadow_viewdepthtexture = viewdepthtexture;
5910         r_shadow_viewcolortexture = viewcolortexture;
5911         r_shadow_viewx = viewx;
5912         r_shadow_viewy = viewy;
5913         r_shadow_viewwidth = viewwidth;
5914         r_shadow_viewheight = viewheight;
5915
5916         R_Shadow_PrepareModelShadows();
5917         R_Shadow_PrepareLights();
5918         if (r_timereport_active)
5919                 R_TimeReport("preparelights");
5920
5921         // render all the shadowmaps that will be used for this view
5922         shadowmapping = R_Shadow_ShadowMappingEnabled();
5923         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5924         {
5925                 R_Shadow_DrawShadowMaps();
5926                 if (r_timereport_active)
5927                         R_TimeReport("shadowmaps");
5928         }
5929
5930         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5931         if (r_shadow_usingdeferredprepass)
5932                 R_Shadow_DrawPrepass();
5933
5934         // now we begin the forward pass of the view render
5935         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5936         {
5937                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5938                 if (r_timereport_active)
5939                         R_TimeReport("worlddepth");
5940         }
5941         if (r_depthfirst.integer >= 2)
5942         {
5943                 R_DrawModelsDepth();
5944                 if (r_timereport_active)
5945                         R_TimeReport("modeldepth");
5946         }
5947
5948         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5949         {
5950                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5951                 if (r_timereport_active)
5952                         R_TimeReport("world");
5953         }
5954
5955         // don't let sound skip if going slow
5956         if (r_refdef.scene.extraupdate)
5957                 S_ExtraUpdate ();
5958
5959         R_DrawModels();
5960         if (r_timereport_active)
5961                 R_TimeReport("models");
5962
5963         // don't let sound skip if going slow
5964         if (r_refdef.scene.extraupdate)
5965                 S_ExtraUpdate ();
5966
5967         if (!r_shadow_usingdeferredprepass)
5968         {
5969                 R_Shadow_DrawLights();
5970                 if (r_timereport_active)
5971                         R_TimeReport("rtlights");
5972         }
5973
5974         // don't let sound skip if going slow
5975         if (r_refdef.scene.extraupdate)
5976                 S_ExtraUpdate ();
5977
5978         if (cl.csqc_vidvars.drawworld)
5979         {
5980                 R_DrawModelDecals();
5981                 if (r_timereport_active)
5982                         R_TimeReport("modeldecals");
5983
5984                 R_DrawParticles();
5985                 if (r_timereport_active)
5986                         R_TimeReport("particles");
5987
5988                 R_DrawExplosions();
5989                 if (r_timereport_active)
5990                         R_TimeReport("explosions");
5991         }
5992
5993         if (r_refdef.view.showdebug)
5994         {
5995                 if (cl_locs_show.integer)
5996                 {
5997                         R_DrawLocs();
5998                         if (r_timereport_active)
5999                                 R_TimeReport("showlocs");
6000                 }
6001
6002                 if (r_drawportals.integer)
6003                 {
6004                         R_DrawPortals();
6005                         if (r_timereport_active)
6006                                 R_TimeReport("portals");
6007                 }
6008
6009                 if (r_showbboxes_client.value > 0)
6010                 {
6011                         R_DrawEntityBBoxes(CLVM_prog);
6012                         if (r_timereport_active)
6013                                 R_TimeReport("clbboxes");
6014                 }
6015                 if (r_showbboxes.value > 0)
6016                 {
6017                         R_DrawEntityBBoxes(SVVM_prog);
6018                         if (r_timereport_active)
6019                                 R_TimeReport("svbboxes");
6020                 }
6021         }
6022
6023         if (r_transparent.integer)
6024         {
6025                 R_MeshQueue_RenderTransparent();
6026                 if (r_timereport_active)
6027                         R_TimeReport("drawtrans");
6028         }
6029
6030         if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0 || r_showoverdraw.value > 0))
6031         {
6032                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6033                 if (r_timereport_active)
6034                         R_TimeReport("worlddebug");
6035                 R_DrawModelsDebug();
6036                 if (r_timereport_active)
6037                         R_TimeReport("modeldebug");
6038         }
6039
6040         if (cl.csqc_vidvars.drawworld)
6041         {
6042                 R_Shadow_DrawCoronas();
6043                 if (r_timereport_active)
6044                         R_TimeReport("coronas");
6045         }
6046
6047         // don't let sound skip if going slow
6048         if (r_refdef.scene.extraupdate)
6049                 S_ExtraUpdate ();
6050 }
6051
6052 static const unsigned short bboxelements[36] =
6053 {
6054         5, 1, 3, 5, 3, 7,
6055         6, 2, 0, 6, 0, 4,
6056         7, 3, 2, 7, 2, 6,
6057         4, 0, 1, 4, 1, 5,
6058         4, 5, 7, 4, 7, 6,
6059         1, 0, 2, 1, 2, 3,
6060 };
6061
6062 #define BBOXEDGES 13
6063 static const float bboxedges[BBOXEDGES][6] = 
6064 {
6065         // whole box
6066         { 0, 0, 0, 1, 1, 1 },
6067         // bottom edges
6068         { 0, 0, 0, 0, 1, 0 },
6069         { 0, 0, 0, 1, 0, 0 },
6070         { 0, 1, 0, 1, 1, 0 },
6071         { 1, 0, 0, 1, 1, 0 },
6072         // top edges
6073         { 0, 0, 1, 0, 1, 1 },
6074         { 0, 0, 1, 1, 0, 1 },
6075         { 0, 1, 1, 1, 1, 1 },
6076         { 1, 0, 1, 1, 1, 1 },
6077         // vertical edges
6078         { 0, 0, 0, 0, 0, 1 },
6079         { 1, 0, 0, 1, 0, 1 },
6080         { 0, 1, 0, 0, 1, 1 },
6081         { 1, 1, 0, 1, 1, 1 },
6082 };
6083
6084 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6085 {
6086         int numvertices = BBOXEDGES * 8;
6087         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6088         int numtriangles = BBOXEDGES * 12;
6089         unsigned short elements[BBOXEDGES * 36];
6090         int i, edge;
6091         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6092
6093         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6094
6095         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6096         GL_DepthMask(false);
6097         GL_DepthRange(0, 1);
6098         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6099
6100         for (edge = 0; edge < BBOXEDGES; edge++)
6101         {
6102                 for (i = 0; i < 3; i++)
6103                 {
6104                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6105                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6106                 }
6107                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6108                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6109                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6110                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6111                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6112                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6113                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6114                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6115                 for (i = 0; i < 36; i++)
6116                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6117         }
6118         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6119         if (r_refdef.fogenabled)
6120         {
6121                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6122                 {
6123                         f1 = RSurf_FogVertex(v);
6124                         f2 = 1 - f1;
6125                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6126                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6127                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6128                 }
6129         }
6130         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6131         R_Mesh_ResetTextureState();
6132         R_SetupShader_Generic_NoTexture(false, false);
6133         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6134 }
6135
6136 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6137 {
6138         // hacky overloading of the parameters
6139         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6140         int i;
6141         float color[4];
6142         prvm_edict_t *edict;
6143
6144         GL_CullFace(GL_NONE);
6145         R_SetupShader_Generic_NoTexture(false, false);
6146
6147         for (i = 0;i < numsurfaces;i++)
6148         {
6149                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6150                 switch ((int)PRVM_serveredictfloat(edict, solid))
6151                 {
6152                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6153                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6154                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6155                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6156                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6157                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6158                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6159                 }
6160                 if (prog == CLVM_prog)
6161                         color[3] *= r_showbboxes_client.value;
6162                 else
6163                         color[3] *= r_showbboxes.value;
6164                 color[3] = bound(0, color[3], 1);
6165                 GL_DepthTest(!r_showdisabledepthtest.integer);
6166                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6167         }
6168 }
6169
6170 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6171 {
6172         int i;
6173         prvm_edict_t *edict;
6174         vec3_t center;
6175
6176         if (prog == NULL)
6177                 return;
6178
6179         for (i = 0; i < prog->num_edicts; i++)
6180         {
6181                 edict = PRVM_EDICT_NUM(i);
6182                 if (edict->priv.server->free)
6183                         continue;
6184                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6185                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6186                         continue;
6187                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6188                         continue;
6189                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6190                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6191         }
6192 }
6193
6194 static const int nomodelelement3i[24] =
6195 {
6196         5, 2, 0,
6197         5, 1, 2,
6198         5, 0, 3,
6199         5, 3, 1,
6200         0, 2, 4,
6201         2, 1, 4,
6202         3, 0, 4,
6203         1, 3, 4
6204 };
6205
6206 static const unsigned short nomodelelement3s[24] =
6207 {
6208         5, 2, 0,
6209         5, 1, 2,
6210         5, 0, 3,
6211         5, 3, 1,
6212         0, 2, 4,
6213         2, 1, 4,
6214         3, 0, 4,
6215         1, 3, 4
6216 };
6217
6218 static const float nomodelvertex3f[6*3] =
6219 {
6220         -16,   0,   0,
6221          16,   0,   0,
6222           0, -16,   0,
6223           0,  16,   0,
6224           0,   0, -16,
6225           0,   0,  16
6226 };
6227
6228 static const float nomodelcolor4f[6*4] =
6229 {
6230         0.0f, 0.0f, 0.5f, 1.0f,
6231         0.0f, 0.0f, 0.5f, 1.0f,
6232         0.0f, 0.5f, 0.0f, 1.0f,
6233         0.0f, 0.5f, 0.0f, 1.0f,
6234         0.5f, 0.0f, 0.0f, 1.0f,
6235         0.5f, 0.0f, 0.0f, 1.0f
6236 };
6237
6238 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6239 {
6240         int i;
6241         float f1, f2, *c;
6242         float color4f[6*4];
6243
6244         RSurf_ActiveCustomEntity(&ent->matrix, &ent->inversematrix, ent->flags, ent->shadertime, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha, 6, nomodelvertex3f, NULL, NULL, NULL, NULL, nomodelcolor4f, 8, nomodelelement3i, nomodelelement3s, false, false);
6245
6246         // this is only called once per entity so numsurfaces is always 1, and
6247         // surfacelist is always {0}, so this code does not handle batches
6248
6249         if (rsurface.ent_flags & RENDER_ADDITIVE)
6250         {
6251                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6252                 GL_DepthMask(false);
6253         }
6254         else if (ent->alpha < 1)
6255         {
6256                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6257                 GL_DepthMask(false);
6258         }
6259         else
6260         {
6261                 GL_BlendFunc(GL_ONE, GL_ZERO);
6262                 GL_DepthMask(true);
6263         }
6264         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6265         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6266         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6267         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6268         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6269         for (i = 0, c = color4f;i < 6;i++, c += 4)
6270         {
6271                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6272                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6273                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6274                 c[3] *= ent->alpha;
6275         }
6276         if (r_refdef.fogenabled)
6277         {
6278                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6279                 {
6280                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6281                         f2 = 1 - f1;
6282                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6283                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6284                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6285                 }
6286         }
6287 //      R_Mesh_ResetTextureState();
6288         R_SetupShader_Generic_NoTexture(false, false);
6289         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6290         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6291 }
6292
6293 void R_DrawNoModel(entity_render_t *ent)
6294 {
6295         vec3_t org;
6296         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6297         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6298                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6299         else
6300                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6301 }
6302
6303 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6304 {
6305         vec3_t right1, right2, diff, normal;
6306
6307         VectorSubtract (org2, org1, normal);
6308
6309         // calculate 'right' vector for start
6310         VectorSubtract (r_refdef.view.origin, org1, diff);
6311         CrossProduct (normal, diff, right1);
6312         VectorNormalize (right1);
6313
6314         // calculate 'right' vector for end
6315         VectorSubtract (r_refdef.view.origin, org2, diff);
6316         CrossProduct (normal, diff, right2);
6317         VectorNormalize (right2);
6318
6319         vert[ 0] = org1[0] + width * right1[0];
6320         vert[ 1] = org1[1] + width * right1[1];
6321         vert[ 2] = org1[2] + width * right1[2];
6322         vert[ 3] = org1[0] - width * right1[0];
6323         vert[ 4] = org1[1] - width * right1[1];
6324         vert[ 5] = org1[2] - width * right1[2];
6325         vert[ 6] = org2[0] - width * right2[0];
6326         vert[ 7] = org2[1] - width * right2[1];
6327         vert[ 8] = org2[2] - width * right2[2];
6328         vert[ 9] = org2[0] + width * right2[0];
6329         vert[10] = org2[1] + width * right2[1];
6330         vert[11] = org2[2] + width * right2[2];
6331 }
6332
6333 void R_CalcSprite_Vertex3f(float *vertex3f, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2)
6334 {
6335         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6336         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6337         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6338         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6339         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6340         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6341         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6342         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6343         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6344         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6345         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6346         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6347 }
6348
6349 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6350 {
6351         int i;
6352         float *vertex3f;
6353         float v[3];
6354         VectorSet(v, x, y, z);
6355         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6356                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6357                         break;
6358         if (i == mesh->numvertices)
6359         {
6360                 if (mesh->numvertices < mesh->maxvertices)
6361                 {
6362                         VectorCopy(v, vertex3f);
6363                         mesh->numvertices++;
6364                 }
6365                 return mesh->numvertices;
6366         }
6367         else
6368                 return i;
6369 }
6370
6371 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6372 {
6373         int i;
6374         int *e, element[3];
6375         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6376         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6377         e = mesh->element3i + mesh->numtriangles * 3;
6378         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6379         {
6380                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6381                 if (mesh->numtriangles < mesh->maxtriangles)
6382                 {
6383                         *e++ = element[0];
6384                         *e++ = element[1];
6385                         *e++ = element[2];
6386                         mesh->numtriangles++;
6387                 }
6388                 element[1] = element[2];
6389         }
6390 }
6391
6392 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6393 {
6394         int i;
6395         int *e, element[3];
6396         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6397         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6398         e = mesh->element3i + mesh->numtriangles * 3;
6399         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6400         {
6401                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6402                 if (mesh->numtriangles < mesh->maxtriangles)
6403                 {
6404                         *e++ = element[0];
6405                         *e++ = element[1];
6406                         *e++ = element[2];
6407                         mesh->numtriangles++;
6408                 }
6409                 element[1] = element[2];
6410         }
6411 }
6412
6413 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6414 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6415 {
6416         int planenum, planenum2;
6417         int w;
6418         int tempnumpoints;
6419         mplane_t *plane, *plane2;
6420         double maxdist;
6421         double temppoints[2][256*3];
6422         // figure out how large a bounding box we need to properly compute this brush
6423         maxdist = 0;
6424         for (w = 0;w < numplanes;w++)
6425                 maxdist = max(maxdist, fabs(planes[w].dist));
6426         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6427         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6428         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6429         {
6430                 w = 0;
6431                 tempnumpoints = 4;
6432                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6433                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6434                 {
6435                         if (planenum2 == planenum)
6436                                 continue;
6437                         PolygonD_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, R_MESH_PLANE_DIST_EPSILON, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints, NULL);
6438                         w = !w;
6439                 }
6440                 if (tempnumpoints < 3)
6441                         continue;
6442                 // generate elements forming a triangle fan for this polygon
6443                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6444         }
6445 }
6446
6447 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6448 {
6449         if(parms[0] == 0 && parms[1] == 0)
6450                 return false;
6451         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6452                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6453                         return false;
6454         return true;
6455 }
6456
6457 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6458 {
6459         double index, f;
6460         index = parms[2] + rsurface.shadertime * parms[3];
6461         index -= floor(index);
6462         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6463         {
6464         default:
6465         case Q3WAVEFUNC_NONE:
6466         case Q3WAVEFUNC_NOISE:
6467         case Q3WAVEFUNC_COUNT:
6468                 f = 0;
6469                 break;
6470         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6471         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6472         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6473         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6474         case Q3WAVEFUNC_TRIANGLE:
6475                 index *= 4;
6476                 f = index - floor(index);
6477                 if (index < 1)
6478                 {
6479                         // f = f;
6480                 }
6481                 else if (index < 2)
6482                         f = 1 - f;
6483                 else if (index < 3)
6484                         f = -f;
6485                 else
6486                         f = -(1 - f);
6487                 break;
6488         }
6489         f = parms[0] + parms[1] * f;
6490         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6491                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6492         return (float) f;
6493 }
6494
6495 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6496 {
6497         int w, h, idx;
6498         float shadertime;
6499         float f;
6500         float offsetd[2];
6501         float tcmat[12];
6502         matrix4x4_t matrix, temp;
6503         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6504         // it's better to have one huge fixup every 9 hours than gradual
6505         // degradation over time which looks consistently bad after many hours.
6506         //
6507         // tcmod scroll in particular suffers from this degradation which can't be
6508         // effectively worked around even with floor() tricks because we don't
6509         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6510         // a workaround involving floor() would be incorrect anyway...
6511         shadertime = rsurface.shadertime;
6512         if (shadertime >= 32768.0f)
6513                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6514         switch(tcmod->tcmod)
6515         {
6516                 case Q3TCMOD_COUNT:
6517                 case Q3TCMOD_NONE:
6518                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6519                                 matrix = r_waterscrollmatrix;
6520                         else
6521                                 matrix = identitymatrix;
6522                         break;
6523                 case Q3TCMOD_ENTITYTRANSLATE:
6524                         // this is used in Q3 to allow the gamecode to control texcoord
6525                         // scrolling on the entity, which is not supported in darkplaces yet.
6526                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6527                         break;
6528                 case Q3TCMOD_ROTATE:
6529                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6530                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6531                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6532                         break;
6533                 case Q3TCMOD_SCALE:
6534                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6535                         break;
6536                 case Q3TCMOD_SCROLL:
6537                         // this particular tcmod is a "bug for bug" compatible one with regards to
6538                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6539                         // specifically did the wrapping and so we must mimic that...
6540                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6541                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6542                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6543                         break;
6544                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6545                         w = (int) tcmod->parms[0];
6546                         h = (int) tcmod->parms[1];
6547                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6548                         f = f - floor(f);
6549                         idx = (int) floor(f * w * h);
6550                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6551                         break;
6552                 case Q3TCMOD_STRETCH:
6553                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6554                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6555                         break;
6556                 case Q3TCMOD_TRANSFORM:
6557                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6558                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6559                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6560                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6561                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6562                         break;
6563                 case Q3TCMOD_TURBULENT:
6564                         // this is handled in the RSurf_PrepareVertices function
6565                         matrix = identitymatrix;
6566                         break;
6567         }
6568         temp = *texmatrix;
6569         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6570 }
6571
6572 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6573 {
6574         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6575         char name[MAX_QPATH];
6576         skinframe_t *skinframe;
6577         unsigned char pixels[296*194];
6578         strlcpy(cache->name, skinname, sizeof(cache->name));
6579         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6580         if (developer_loading.integer)
6581                 Con_Printf("loading %s\n", name);
6582         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6583         if (!skinframe || !skinframe->base)
6584         {
6585                 unsigned char *f;
6586                 fs_offset_t filesize;
6587                 skinframe = NULL;
6588                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6589                 if (f)
6590                 {
6591                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6592                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6593                         Mem_Free(f);
6594                 }
6595         }
6596         cache->skinframe = skinframe;
6597 }
6598
6599 texture_t *R_GetCurrentTexture(texture_t *t)
6600 {
6601         int i, q;
6602         const entity_render_t *ent = rsurface.entity;
6603         model_t *model = ent->model; // when calling this, ent must not be NULL
6604         q3shaderinfo_layer_tcmod_t *tcmod;
6605         float specularscale = 0.0f;
6606
6607         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6608                 return t->currentframe;
6609         t->update_lastrenderframe = r_textureframe;
6610         t->update_lastrenderentity = (void *)ent;
6611
6612         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6613                 t->camera_entity = ent->entitynumber;
6614         else
6615                 t->camera_entity = 0;
6616
6617         // switch to an alternate material if this is a q1bsp animated material
6618         {
6619                 texture_t *texture = t;
6620                 int s = rsurface.ent_skinnum;
6621                 if ((unsigned int)s >= (unsigned int)model->numskins)
6622                         s = 0;
6623                 if (model->skinscenes)
6624                 {
6625                         if (model->skinscenes[s].framecount > 1)
6626                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6627                         else
6628                                 s = model->skinscenes[s].firstframe;
6629                 }
6630                 if (s > 0)
6631                         t = t + s * model->num_surfaces;
6632                 if (t->animated)
6633                 {
6634                         // use an alternate animation if the entity's frame is not 0,
6635                         // and only if the texture has an alternate animation
6636                         if (t->animated == 2) // q2bsp
6637                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6638                         else if (rsurface.ent_alttextures && t->anim_total[1])
6639                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6640                         else
6641                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6642                 }
6643                 texture->currentframe = t;
6644         }
6645
6646         // update currentskinframe to be a qw skin or animation frame
6647         if (rsurface.ent_qwskin >= 0)
6648         {
6649                 i = rsurface.ent_qwskin;
6650                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6651                 {
6652                         r_qwskincache_size = cl.maxclients;
6653                         if (r_qwskincache)
6654                                 Mem_Free(r_qwskincache);
6655                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6656                 }
6657                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6658                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6659                 t->currentskinframe = r_qwskincache[i].skinframe;
6660                 if (t->materialshaderpass && t->currentskinframe == NULL)
6661                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6662         }
6663         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6664                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6665         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6666                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6667
6668         t->currentmaterialflags = t->basematerialflags;
6669         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6670         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6671                 t->currentalpha *= r_wateralpha.value;
6672         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6673                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6674         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6675                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6676
6677         // decide on which type of lighting to use for this surface
6678         if (rsurface.entity->render_modellight_forced)
6679                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6680         if (rsurface.entity->render_rtlight_disabled)
6681                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6682         if (rsurface.entity->render_lightgrid)
6683                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6684         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6685         {
6686                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6687                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6688                 for (q = 0; q < 3; q++)
6689                 {
6690                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6691                         t->render_modellight_lightdir_world[q] = q == 2;
6692                         t->render_modellight_lightdir_local[q] = q == 2;
6693                         t->render_modellight_ambient[q] = 1;
6694                         t->render_modellight_diffuse[q] = 0;
6695                         t->render_modellight_specular[q] = 0;
6696                         t->render_lightmap_ambient[q] = 0;
6697                         t->render_lightmap_diffuse[q] = 0;
6698                         t->render_lightmap_specular[q] = 0;
6699                         t->render_rtlight_diffuse[q] = 0;
6700                         t->render_rtlight_specular[q] = 0;
6701                 }
6702         }
6703         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6704         {
6705                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6706                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6707                 for (q = 0; q < 3; q++)
6708                 {
6709                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6710                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6711                         t->render_modellight_lightdir_world[q] = q == 2;
6712                         t->render_modellight_lightdir_local[q] = q == 2;
6713                         t->render_modellight_diffuse[q] = 0;
6714                         t->render_modellight_specular[q] = 0;
6715                         t->render_lightmap_ambient[q] = 0;
6716                         t->render_lightmap_diffuse[q] = 0;
6717                         t->render_lightmap_specular[q] = 0;
6718                         t->render_rtlight_diffuse[q] = 0;
6719                         t->render_rtlight_specular[q] = 0;
6720                 }
6721         }
6722         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6723         {
6724                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6725                 for (q = 0; q < 3; q++)
6726                 {
6727                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6728                         t->render_modellight_lightdir_world[q] = q == 2;
6729                         t->render_modellight_lightdir_local[q] = q == 2;
6730                         t->render_modellight_ambient[q] = 0;
6731                         t->render_modellight_diffuse[q] = 0;
6732                         t->render_modellight_specular[q] = 0;
6733                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6734                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6735                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6736                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6737                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6738                 }
6739         }
6740         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6741         {
6742                 // ambient + single direction light (modellight)
6743                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6744                 for (q = 0; q < 3; q++)
6745                 {
6746                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6747                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6748                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6749                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6750                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6751                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6752                         t->render_lightmap_ambient[q] = 0;
6753                         t->render_lightmap_diffuse[q] = 0;
6754                         t->render_lightmap_specular[q] = 0;
6755                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6756                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6757                 }
6758         }
6759         else
6760         {
6761                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6762                 for (q = 0; q < 3; q++)
6763                 {
6764                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6765                         t->render_modellight_lightdir_world[q] = q == 2;
6766                         t->render_modellight_lightdir_local[q] = q == 2;
6767                         t->render_modellight_ambient[q] = 0;
6768                         t->render_modellight_diffuse[q] = 0;
6769                         t->render_modellight_specular[q] = 0;
6770                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6771                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6772                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6773                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6774                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6775                 }
6776         }
6777
6778         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6779         {
6780                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6781                 // attribute, we punt it to the lightmap path and hope for the best,
6782                 // but lighting doesn't work.
6783                 //
6784                 // FIXME: this is fine for effects but CSQC polygons should be subject
6785                 // to lighting.
6786                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6787                 for (q = 0; q < 3; q++)
6788                 {
6789                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6790                         t->render_modellight_lightdir_world[q] = q == 2;
6791                         t->render_modellight_lightdir_local[q] = q == 2;
6792                         t->render_modellight_ambient[q] = 0;
6793                         t->render_modellight_diffuse[q] = 0;
6794                         t->render_modellight_specular[q] = 0;
6795                         t->render_lightmap_ambient[q] = 0;
6796                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6797                         t->render_lightmap_specular[q] = 0;
6798                         t->render_rtlight_diffuse[q] = 0;
6799                         t->render_rtlight_specular[q] = 0;
6800                 }
6801         }
6802
6803         for (q = 0; q < 3; q++)
6804         {
6805                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6806                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6807         }
6808
6809         if (rsurface.ent_flags & RENDER_ADDITIVE)
6810                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6811         else if (t->currentalpha < 1)
6812                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6813         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6814         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6815                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6816         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6817                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6818         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6819                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6820         if (t->backgroundshaderpass)
6821                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6822         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6823         {
6824                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6825                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6826         }
6827         else
6828                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6829         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6830         {
6831                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6832                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6833         }
6834         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6835                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6836
6837         // there is no tcmod
6838         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6839         {
6840                 t->currenttexmatrix = r_waterscrollmatrix;
6841                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6842         }
6843         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6844         {
6845                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6846                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6847         }
6848
6849         if (t->materialshaderpass)
6850                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6851                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6852
6853         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6854         if (t->currentskinframe->qpixels)
6855                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6856         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6857         if (!t->basetexture)
6858                 t->basetexture = r_texture_notexture;
6859         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6860         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6861         t->nmaptexture = t->currentskinframe->nmap;
6862         if (!t->nmaptexture)
6863                 t->nmaptexture = r_texture_blanknormalmap;
6864         t->glosstexture = r_texture_black;
6865         t->glowtexture = t->currentskinframe->glow;
6866         t->fogtexture = t->currentskinframe->fog;
6867         t->reflectmasktexture = t->currentskinframe->reflect;
6868         if (t->backgroundshaderpass)
6869         {
6870                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6871                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6872                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6873                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6874                 t->backgroundglosstexture = r_texture_black;
6875                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6876                 if (!t->backgroundnmaptexture)
6877                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6878                 // make sure that if glow is going to be used, both textures are not NULL
6879                 if (!t->backgroundglowtexture && t->glowtexture)
6880                         t->backgroundglowtexture = r_texture_black;
6881                 if (!t->glowtexture && t->backgroundglowtexture)
6882                         t->glowtexture = r_texture_black;
6883         }
6884         else
6885         {
6886                 t->backgroundbasetexture = r_texture_white;
6887                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6888                 t->backgroundglosstexture = r_texture_black;
6889                 t->backgroundglowtexture = NULL;
6890         }
6891         t->specularpower = r_shadow_glossexponent.value;
6892         // TODO: store reference values for these in the texture?
6893         if (r_shadow_gloss.integer > 0)
6894         {
6895                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6896                 {
6897                         if (r_shadow_glossintensity.value > 0)
6898                         {
6899                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6900                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6901                                 specularscale = r_shadow_glossintensity.value;
6902                         }
6903                 }
6904                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6905                 {
6906                         t->glosstexture = r_texture_white;
6907                         t->backgroundglosstexture = r_texture_white;
6908                         specularscale = r_shadow_gloss2intensity.value;
6909                         t->specularpower = r_shadow_gloss2exponent.value;
6910                 }
6911         }
6912         specularscale *= t->specularscalemod;
6913         t->specularpower *= t->specularpowermod;
6914
6915         // lightmaps mode looks bad with dlights using actual texturing, so turn
6916         // off the colormap and glossmap, but leave the normalmap on as it still
6917         // accurately represents the shading involved
6918         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6919         {
6920                 t->basetexture = r_texture_grey128;
6921                 t->pantstexture = r_texture_black;
6922                 t->shirttexture = r_texture_black;
6923                 if (gl_lightmaps.integer < 2)
6924                         t->nmaptexture = r_texture_blanknormalmap;
6925                 t->glosstexture = r_texture_black;
6926                 t->glowtexture = NULL;
6927                 t->fogtexture = NULL;
6928                 t->reflectmasktexture = NULL;
6929                 t->backgroundbasetexture = NULL;
6930                 if (gl_lightmaps.integer < 2)
6931                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6932                 t->backgroundglosstexture = r_texture_black;
6933                 t->backgroundglowtexture = NULL;
6934                 specularscale = 0;
6935                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6936         }
6937
6938         if (specularscale != 1.0f)
6939         {
6940                 for (q = 0; q < 3; q++)
6941                 {
6942                         t->render_modellight_specular[q] *= specularscale;
6943                         t->render_lightmap_specular[q] *= specularscale;
6944                         t->render_rtlight_specular[q] *= specularscale;
6945                 }
6946         }
6947
6948         t->currentblendfunc[0] = GL_ONE;
6949         t->currentblendfunc[1] = GL_ZERO;
6950         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6951         {
6952                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6953                 t->currentblendfunc[1] = GL_ONE;
6954         }
6955         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6956         {
6957                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6958                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6959         }
6960         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6961         {
6962                 t->currentblendfunc[0] = t->customblendfunc[0];
6963                 t->currentblendfunc[1] = t->customblendfunc[1];
6964         }
6965
6966         return t;
6967 }
6968
6969 rsurfacestate_t rsurface;
6970
6971 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6972 {
6973         model_t *model = ent->model;
6974         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6975         //      return;
6976         rsurface.entity = (entity_render_t *)ent;
6977         rsurface.skeleton = ent->skeleton;
6978         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6979         rsurface.ent_skinnum = ent->skinnum;
6980         rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
6981         rsurface.ent_flags = ent->flags;
6982         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6983                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6984         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6985         rsurface.matrix = ent->matrix;
6986         rsurface.inversematrix = ent->inversematrix;
6987         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6988         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6989         R_EntityMatrix(&rsurface.matrix);
6990         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6991         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6992         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6993         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6994         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6995         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6996         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6997         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6998         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6999         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7000         if (ent->model->brush.submodel && !prepass)
7001         {
7002                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7003                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7004         }
7005         // if the animcache code decided it should use the shader path, skip the deform step
7006         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7007         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7008         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7009         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7010         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7011         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7012         {
7013                 if (ent->animcache_vertex3f)
7014                 {
7015                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7016                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7017                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7018                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7019                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7020                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7021                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7022                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7023                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7024                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7025                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7026                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7027                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7028                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7029                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7030                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7031                 }
7032                 else if (wanttangents)
7033                 {
7034                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7035                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7036                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7037                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7038                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7039                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7040                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7041                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7042                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7043                         rsurface.modelvertex3f_vertexbuffer = NULL;
7044                         rsurface.modelvertex3f_bufferoffset = 0;
7045                         rsurface.modelvertex3f_vertexbuffer = 0;
7046                         rsurface.modelvertex3f_bufferoffset = 0;
7047                         rsurface.modelsvector3f_vertexbuffer = 0;
7048                         rsurface.modelsvector3f_bufferoffset = 0;
7049                         rsurface.modeltvector3f_vertexbuffer = 0;
7050                         rsurface.modeltvector3f_bufferoffset = 0;
7051                         rsurface.modelnormal3f_vertexbuffer = 0;
7052                         rsurface.modelnormal3f_bufferoffset = 0;
7053                 }
7054                 else if (wantnormals)
7055                 {
7056                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7057                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7058                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7059                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7060                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7061                         rsurface.modelsvector3f = NULL;
7062                         rsurface.modeltvector3f = NULL;
7063                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7064                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7065                         rsurface.modelvertex3f_vertexbuffer = NULL;
7066                         rsurface.modelvertex3f_bufferoffset = 0;
7067                         rsurface.modelvertex3f_vertexbuffer = 0;
7068                         rsurface.modelvertex3f_bufferoffset = 0;
7069                         rsurface.modelsvector3f_vertexbuffer = 0;
7070                         rsurface.modelsvector3f_bufferoffset = 0;
7071                         rsurface.modeltvector3f_vertexbuffer = 0;
7072                         rsurface.modeltvector3f_bufferoffset = 0;
7073                         rsurface.modelnormal3f_vertexbuffer = 0;
7074                         rsurface.modelnormal3f_bufferoffset = 0;
7075                 }
7076                 else
7077                 {
7078                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7079                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7080                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7081                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7082                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7083                         rsurface.modelsvector3f = NULL;
7084                         rsurface.modeltvector3f = NULL;
7085                         rsurface.modelnormal3f = NULL;
7086                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7087                         rsurface.modelvertex3f_vertexbuffer = NULL;
7088                         rsurface.modelvertex3f_bufferoffset = 0;
7089                         rsurface.modelvertex3f_vertexbuffer = 0;
7090                         rsurface.modelvertex3f_bufferoffset = 0;
7091                         rsurface.modelsvector3f_vertexbuffer = 0;
7092                         rsurface.modelsvector3f_bufferoffset = 0;
7093                         rsurface.modeltvector3f_vertexbuffer = 0;
7094                         rsurface.modeltvector3f_bufferoffset = 0;
7095                         rsurface.modelnormal3f_vertexbuffer = 0;
7096                         rsurface.modelnormal3f_bufferoffset = 0;
7097                 }
7098                 rsurface.modelgeneratedvertex = true;
7099         }
7100         else
7101         {
7102                 if (rsurface.entityskeletaltransform3x4)
7103                 {
7104                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7105                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7106                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7107                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7108                 }
7109                 else
7110                 {
7111                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7112                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7113                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7114                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7115                 }
7116                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7117                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7118                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7119                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7120                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7121                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7122                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7123                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7124                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7125                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7126                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7127                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7128                 rsurface.modelgeneratedvertex = false;
7129         }
7130         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7131         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7132         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7133         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7134         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7135         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7136         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7137         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7138         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7139         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7140         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7141         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7142         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7143         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7144         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7145         rsurface.modelelement3i = model->surfmesh.data_element3i;
7146         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7147         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7148         rsurface.modelelement3s = model->surfmesh.data_element3s;
7149         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7150         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7151         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7152         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7153         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7154         rsurface.modelsurfaces = model->data_surfaces;
7155         rsurface.batchgeneratedvertex = false;
7156         rsurface.batchfirstvertex = 0;
7157         rsurface.batchnumvertices = 0;
7158         rsurface.batchfirsttriangle = 0;
7159         rsurface.batchnumtriangles = 0;
7160         rsurface.batchvertex3f  = NULL;
7161         rsurface.batchvertex3f_vertexbuffer = NULL;
7162         rsurface.batchvertex3f_bufferoffset = 0;
7163         rsurface.batchsvector3f = NULL;
7164         rsurface.batchsvector3f_vertexbuffer = NULL;
7165         rsurface.batchsvector3f_bufferoffset = 0;
7166         rsurface.batchtvector3f = NULL;
7167         rsurface.batchtvector3f_vertexbuffer = NULL;
7168         rsurface.batchtvector3f_bufferoffset = 0;
7169         rsurface.batchnormal3f  = NULL;
7170         rsurface.batchnormal3f_vertexbuffer = NULL;
7171         rsurface.batchnormal3f_bufferoffset = 0;
7172         rsurface.batchlightmapcolor4f = NULL;
7173         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7174         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7175         rsurface.batchtexcoordtexture2f = NULL;
7176         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7177         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7178         rsurface.batchtexcoordlightmap2f = NULL;
7179         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7180         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7181         rsurface.batchskeletalindex4ub = NULL;
7182         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7183         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7184         rsurface.batchskeletalweight4ub = NULL;
7185         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7186         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7187         rsurface.batchelement3i = NULL;
7188         rsurface.batchelement3i_indexbuffer = NULL;
7189         rsurface.batchelement3i_bufferoffset = 0;
7190         rsurface.batchelement3s = NULL;
7191         rsurface.batchelement3s_indexbuffer = NULL;
7192         rsurface.batchelement3s_bufferoffset = 0;
7193         rsurface.forcecurrenttextureupdate = false;
7194 }
7195
7196 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qbool wantnormals, qbool wanttangents)
7197 {
7198         rsurface.entity = r_refdef.scene.worldentity;
7199         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7200                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7201                 // A better approach could be making this copy only once per frame.
7202                 static entity_render_t custom_entity;
7203                 int q;
7204                 custom_entity = *rsurface.entity;
7205                 for (q = 0; q < 3; ++q) {
7206                         float colormod = q == 0 ? r : q == 1 ? g : b;
7207                         custom_entity.render_fullbright[q] *= colormod;
7208                         custom_entity.render_modellight_ambient[q] *= colormod;
7209                         custom_entity.render_modellight_diffuse[q] *= colormod;
7210                         custom_entity.render_lightmap_ambient[q] *= colormod;
7211                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7212                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7213                 }
7214                 custom_entity.alpha *= a;
7215                 rsurface.entity = &custom_entity;
7216         }
7217         rsurface.skeleton = NULL;
7218         rsurface.ent_skinnum = 0;
7219         rsurface.ent_qwskin = -1;
7220         rsurface.ent_flags = entflags;
7221         rsurface.shadertime = r_refdef.scene.time - shadertime;
7222         rsurface.modelnumvertices = numvertices;
7223         rsurface.modelnumtriangles = numtriangles;
7224         rsurface.matrix = *matrix;
7225         rsurface.inversematrix = *inversematrix;
7226         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7227         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7228         R_EntityMatrix(&rsurface.matrix);
7229         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7230         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7231         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7232         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7233         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7234         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7235         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7236         rsurface.frameblend[0].lerp = 1;
7237         rsurface.ent_alttextures = false;
7238         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7239         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7240         rsurface.entityskeletaltransform3x4 = NULL;
7241         rsurface.entityskeletaltransform3x4buffer = NULL;
7242         rsurface.entityskeletaltransform3x4offset = 0;
7243         rsurface.entityskeletaltransform3x4size = 0;
7244         rsurface.entityskeletalnumtransforms = 0;
7245         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7246         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7247         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7248         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7249         if (wanttangents)
7250         {
7251                 rsurface.modelvertex3f = (float *)vertex3f;
7252                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7253                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7254                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7255         }
7256         else if (wantnormals)
7257         {
7258                 rsurface.modelvertex3f = (float *)vertex3f;
7259                 rsurface.modelsvector3f = NULL;
7260                 rsurface.modeltvector3f = NULL;
7261                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7262         }
7263         else
7264         {
7265                 rsurface.modelvertex3f = (float *)vertex3f;
7266                 rsurface.modelsvector3f = NULL;
7267                 rsurface.modeltvector3f = NULL;
7268                 rsurface.modelnormal3f = NULL;
7269         }
7270         rsurface.modelvertex3f_vertexbuffer = 0;
7271         rsurface.modelvertex3f_bufferoffset = 0;
7272         rsurface.modelsvector3f_vertexbuffer = 0;
7273         rsurface.modelsvector3f_bufferoffset = 0;
7274         rsurface.modeltvector3f_vertexbuffer = 0;
7275         rsurface.modeltvector3f_bufferoffset = 0;
7276         rsurface.modelnormal3f_vertexbuffer = 0;
7277         rsurface.modelnormal3f_bufferoffset = 0;
7278         rsurface.modelgeneratedvertex = true;
7279         rsurface.modellightmapcolor4f  = (float *)color4f;
7280         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7281         rsurface.modellightmapcolor4f_bufferoffset = 0;
7282         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7283         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7284         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7285         rsurface.modeltexcoordlightmap2f  = NULL;
7286         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7287         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7288         rsurface.modelskeletalindex4ub = NULL;
7289         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7290         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7291         rsurface.modelskeletalweight4ub = NULL;
7292         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7293         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7294         rsurface.modelelement3i = (int *)element3i;
7295         rsurface.modelelement3i_indexbuffer = NULL;
7296         rsurface.modelelement3i_bufferoffset = 0;
7297         rsurface.modelelement3s = (unsigned short *)element3s;
7298         rsurface.modelelement3s_indexbuffer = NULL;
7299         rsurface.modelelement3s_bufferoffset = 0;
7300         rsurface.modellightmapoffsets = NULL;
7301         rsurface.modelsurfaces = NULL;
7302         rsurface.batchgeneratedvertex = false;
7303         rsurface.batchfirstvertex = 0;
7304         rsurface.batchnumvertices = 0;
7305         rsurface.batchfirsttriangle = 0;
7306         rsurface.batchnumtriangles = 0;
7307         rsurface.batchvertex3f  = NULL;
7308         rsurface.batchvertex3f_vertexbuffer = NULL;
7309         rsurface.batchvertex3f_bufferoffset = 0;
7310         rsurface.batchsvector3f = NULL;
7311         rsurface.batchsvector3f_vertexbuffer = NULL;
7312         rsurface.batchsvector3f_bufferoffset = 0;
7313         rsurface.batchtvector3f = NULL;
7314         rsurface.batchtvector3f_vertexbuffer = NULL;
7315         rsurface.batchtvector3f_bufferoffset = 0;
7316         rsurface.batchnormal3f  = NULL;
7317         rsurface.batchnormal3f_vertexbuffer = NULL;
7318         rsurface.batchnormal3f_bufferoffset = 0;
7319         rsurface.batchlightmapcolor4f = NULL;
7320         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7321         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7322         rsurface.batchtexcoordtexture2f = NULL;
7323         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7324         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7325         rsurface.batchtexcoordlightmap2f = NULL;
7326         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7327         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7328         rsurface.batchskeletalindex4ub = NULL;
7329         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7330         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7331         rsurface.batchskeletalweight4ub = NULL;
7332         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7333         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7334         rsurface.batchelement3i = NULL;
7335         rsurface.batchelement3i_indexbuffer = NULL;
7336         rsurface.batchelement3i_bufferoffset = 0;
7337         rsurface.batchelement3s = NULL;
7338         rsurface.batchelement3s_indexbuffer = NULL;
7339         rsurface.batchelement3s_bufferoffset = 0;
7340         rsurface.forcecurrenttextureupdate = true;
7341
7342         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7343         {
7344                 if ((wantnormals || wanttangents) && !normal3f)
7345                 {
7346                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7347                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7348                 }
7349                 if (wanttangents && !svector3f)
7350                 {
7351                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7352                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7353                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7354                 }
7355         }
7356 }
7357
7358 float RSurf_FogPoint(const float *v)
7359 {
7360         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7361         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7362         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7363         float FogHeightFade = r_refdef.fogheightfade;
7364         float fogfrac;
7365         unsigned int fogmasktableindex;
7366         if (r_refdef.fogplaneviewabove)
7367                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7368         else
7369                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7370         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7371         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7372 }
7373
7374 float RSurf_FogVertex(const float *v)
7375 {
7376         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7377         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7378         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7379         float FogHeightFade = rsurface.fogheightfade;
7380         float fogfrac;
7381         unsigned int fogmasktableindex;
7382         if (r_refdef.fogplaneviewabove)
7383                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7384         else
7385                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7386         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7387         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7388 }
7389
7390 void RSurf_UploadBuffersForBatch(void)
7391 {
7392         // upload buffer data for generated vertex data (dynamicvertex case) or index data (copytriangles case) and models that lack it to begin with (e.g. DrawQ_FlushUI)
7393         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7394         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7395                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7396         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7397                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7398         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7399                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7400         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7401                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7402         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7403                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7404         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7405                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7406         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7407                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7408         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7409                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7410         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7411                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7412
7413         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7414                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7415         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7416                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7417
7418         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7419         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7420         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7421         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7422         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7423         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7424         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7425         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7426         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7427         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7428 }
7429
7430 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7431 {
7432         int i;
7433         for (i = 0;i < numelements;i++)
7434                 outelement3i[i] = inelement3i[i] + adjust;
7435 }
7436
7437 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7438 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7439 {
7440         int deformindex;
7441         int firsttriangle;
7442         int numtriangles;
7443         int firstvertex;
7444         int endvertex;
7445         int numvertices;
7446         int surfacefirsttriangle;
7447         int surfacenumtriangles;
7448         int surfacefirstvertex;
7449         int surfaceendvertex;
7450         int surfacenumvertices;
7451         int batchnumsurfaces = texturenumsurfaces;
7452         int batchnumvertices;
7453         int batchnumtriangles;
7454         int i, j;
7455         qbool gaps;
7456         qbool dynamicvertex;
7457         float amplitude;
7458         float animpos;
7459         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7460         float waveparms[4];
7461         unsigned char *ub;
7462         q3shaderinfo_deform_t *deform;
7463         const msurface_t *surface, *firstsurface;
7464         if (!texturenumsurfaces)
7465                 return;
7466         // find vertex range of this surface batch
7467         gaps = false;
7468         firstsurface = texturesurfacelist[0];
7469         firsttriangle = firstsurface->num_firsttriangle;
7470         batchnumvertices = 0;
7471         batchnumtriangles = 0;
7472         firstvertex = endvertex = firstsurface->num_firstvertex;
7473         for (i = 0;i < texturenumsurfaces;i++)
7474         {
7475                 surface = texturesurfacelist[i];
7476                 if (surface != firstsurface + i)
7477                         gaps = true;
7478                 surfacefirstvertex = surface->num_firstvertex;
7479                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7480                 surfacenumvertices = surface->num_vertices;
7481                 surfacenumtriangles = surface->num_triangles;
7482                 if (firstvertex > surfacefirstvertex)
7483                         firstvertex = surfacefirstvertex;
7484                 if (endvertex < surfaceendvertex)
7485                         endvertex = surfaceendvertex;
7486                 batchnumvertices += surfacenumvertices;
7487                 batchnumtriangles += surfacenumtriangles;
7488         }
7489
7490         r_refdef.stats[r_stat_batch_batches]++;
7491         if (gaps)
7492                 r_refdef.stats[r_stat_batch_withgaps]++;
7493         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7494         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7495         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7496
7497         // we now know the vertex range used, and if there are any gaps in it
7498         rsurface.batchfirstvertex = firstvertex;
7499         rsurface.batchnumvertices = endvertex - firstvertex;
7500         rsurface.batchfirsttriangle = firsttriangle;
7501         rsurface.batchnumtriangles = batchnumtriangles;
7502
7503         // check if any dynamic vertex processing must occur
7504         dynamicvertex = false;
7505
7506         // we must use vertexbuffers for rendering, we can upload vertex buffers
7507         // easily enough but if the basevertex is non-zero it becomes more
7508         // difficult, so force dynamicvertex path in that case - it's suboptimal
7509         // but the most optimal case is to have the geometry sources provide their
7510         // own anyway.
7511         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7512                 dynamicvertex = true;
7513
7514         // a cvar to force the dynamic vertex path to be taken, for debugging
7515         if (r_batch_debugdynamicvertexpath.integer)
7516         {
7517                 if (!dynamicvertex)
7518                 {
7519                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7520                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7521                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7522                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7523                 }
7524                 dynamicvertex = true;
7525         }
7526
7527         // if there is a chance of animated vertex colors, it's a dynamic batch
7528         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7529         {
7530                 if (!dynamicvertex)
7531                 {
7532                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7533                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7534                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7535                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7536                 }
7537                 dynamicvertex = true;
7538         }
7539
7540         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7541         {
7542                 switch (deform->deform)
7543                 {
7544                 default:
7545                 case Q3DEFORM_PROJECTIONSHADOW:
7546                 case Q3DEFORM_TEXT0:
7547                 case Q3DEFORM_TEXT1:
7548                 case Q3DEFORM_TEXT2:
7549                 case Q3DEFORM_TEXT3:
7550                 case Q3DEFORM_TEXT4:
7551                 case Q3DEFORM_TEXT5:
7552                 case Q3DEFORM_TEXT6:
7553                 case Q3DEFORM_TEXT7:
7554                 case Q3DEFORM_NONE:
7555                         break;
7556                 case Q3DEFORM_AUTOSPRITE:
7557                         if (!dynamicvertex)
7558                         {
7559                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7560                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7561                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7562                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7563                         }
7564                         dynamicvertex = true;
7565                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7566                         break;
7567                 case Q3DEFORM_AUTOSPRITE2:
7568                         if (!dynamicvertex)
7569                         {
7570                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7571                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7572                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7573                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7574                         }
7575                         dynamicvertex = true;
7576                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7577                         break;
7578                 case Q3DEFORM_NORMAL:
7579                         if (!dynamicvertex)
7580                         {
7581                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7582                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7583                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7584                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7585                         }
7586                         dynamicvertex = true;
7587                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7588                         break;
7589                 case Q3DEFORM_WAVE:
7590                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7591                                 break; // if wavefunc is a nop, ignore this transform
7592                         if (!dynamicvertex)
7593                         {
7594                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7595                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7596                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7597                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7598                         }
7599                         dynamicvertex = true;
7600                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7601                         break;
7602                 case Q3DEFORM_BULGE:
7603                         if (!dynamicvertex)
7604                         {
7605                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7606                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7607                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7608                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7609                         }
7610                         dynamicvertex = true;
7611                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7612                         break;
7613                 case Q3DEFORM_MOVE:
7614                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7615                                 break; // if wavefunc is a nop, ignore this transform
7616                         if (!dynamicvertex)
7617                         {
7618                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7619                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7620                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7621                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7622                         }
7623                         dynamicvertex = true;
7624                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7625                         break;
7626                 }
7627         }
7628         if (rsurface.texture->materialshaderpass)
7629         {
7630                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7631                 {
7632                 default:
7633                 case Q3TCGEN_TEXTURE:
7634                         break;
7635                 case Q3TCGEN_LIGHTMAP:
7636                         if (!dynamicvertex)
7637                         {
7638                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7639                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7640                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7641                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7642                         }
7643                         dynamicvertex = true;
7644                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7645                         break;
7646                 case Q3TCGEN_VECTOR:
7647                         if (!dynamicvertex)
7648                         {
7649                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7650                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7651                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7652                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7653                         }
7654                         dynamicvertex = true;
7655                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7656                         break;
7657                 case Q3TCGEN_ENVIRONMENT:
7658                         if (!dynamicvertex)
7659                         {
7660                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7661                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7662                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7663                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7664                         }
7665                         dynamicvertex = true;
7666                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7667                         break;
7668                 }
7669                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7670                 {
7671                         if (!dynamicvertex)
7672                         {
7673                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7674                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7675                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7676                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7677                         }
7678                         dynamicvertex = true;
7679                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7680                 }
7681         }
7682
7683         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7684         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7685         // we ensure this by treating the vertex batch as dynamic...
7686         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7687         {
7688                 if (!dynamicvertex)
7689                 {
7690                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7691                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7692                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7693                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7694                 }
7695                 dynamicvertex = true;
7696         }
7697
7698         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7699         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7700                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7701
7702         rsurface.batchvertex3f = rsurface.modelvertex3f;
7703         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7704         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7705         rsurface.batchsvector3f = rsurface.modelsvector3f;
7706         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7707         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7708         rsurface.batchtvector3f = rsurface.modeltvector3f;
7709         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7710         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7711         rsurface.batchnormal3f = rsurface.modelnormal3f;
7712         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7713         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7714         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7715         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7716         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7717         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7718         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7719         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7720         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7721         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7722         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7723         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7724         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7725         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7726         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7727         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7728         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7729         rsurface.batchelement3i = rsurface.modelelement3i;
7730         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7731         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7732         rsurface.batchelement3s = rsurface.modelelement3s;
7733         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7734         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7735         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7736         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7737         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7738         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7739         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7740
7741         // if any dynamic vertex processing has to occur in software, we copy the
7742         // entire surface list together before processing to rebase the vertices
7743         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7744         //
7745         // if any gaps exist and we do not have a static vertex buffer, we have to
7746         // copy the surface list together to avoid wasting upload bandwidth on the
7747         // vertices in the gaps.
7748         //
7749         // if gaps exist and we have a static vertex buffer, we can choose whether
7750         // to combine the index buffer ranges into one dynamic index buffer or
7751         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7752         //
7753         // in many cases the batch is reduced to one draw call.
7754
7755         rsurface.batchmultidraw = false;
7756         rsurface.batchmultidrawnumsurfaces = 0;
7757         rsurface.batchmultidrawsurfacelist = NULL;
7758
7759         if (!dynamicvertex)
7760         {
7761                 // static vertex data, just set pointers...
7762                 rsurface.batchgeneratedvertex = false;
7763                 // if there are gaps, we want to build a combined index buffer,
7764                 // otherwise use the original static buffer with an appropriate offset
7765                 if (gaps)
7766                 {
7767                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7768                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7769                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7770                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7771                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7772                         {
7773                                 rsurface.batchmultidraw = true;
7774                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7775                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7776                                 return;
7777                         }
7778                         // build a new triangle elements array for this batch
7779                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7780                         rsurface.batchfirsttriangle = 0;
7781                         numtriangles = 0;
7782                         for (i = 0;i < texturenumsurfaces;i++)
7783                         {
7784                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7785                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7786                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7787                                 numtriangles += surfacenumtriangles;
7788                         }
7789                         rsurface.batchelement3i_indexbuffer = NULL;
7790                         rsurface.batchelement3i_bufferoffset = 0;
7791                         rsurface.batchelement3s = NULL;
7792                         rsurface.batchelement3s_indexbuffer = NULL;
7793                         rsurface.batchelement3s_bufferoffset = 0;
7794                         if (endvertex <= 65536)
7795                         {
7796                                 // make a 16bit (unsigned short) index array if possible
7797                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7798                                 for (i = 0;i < numtriangles*3;i++)
7799                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7800                         }
7801                 }
7802                 else
7803                 {
7804                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7805                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7806                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7807                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7808                 }
7809                 return;
7810         }
7811
7812         // something needs software processing, do it for real...
7813         // we only directly handle separate array data in this case and then
7814         // generate interleaved data if needed...
7815         rsurface.batchgeneratedvertex = true;
7816         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7817         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7818         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7819         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7820
7821         // now copy the vertex data into a combined array and make an index array
7822         // (this is what Quake3 does all the time)
7823         // we also apply any skeletal animation here that would have been done in
7824         // the vertex shader, because most of the dynamic vertex animation cases
7825         // need actual vertex positions and normals
7826         //if (dynamicvertex)
7827         {
7828                 rsurface.batchvertex3f = NULL;
7829                 rsurface.batchvertex3f_vertexbuffer = NULL;
7830                 rsurface.batchvertex3f_bufferoffset = 0;
7831                 rsurface.batchsvector3f = NULL;
7832                 rsurface.batchsvector3f_vertexbuffer = NULL;
7833                 rsurface.batchsvector3f_bufferoffset = 0;
7834                 rsurface.batchtvector3f = NULL;
7835                 rsurface.batchtvector3f_vertexbuffer = NULL;
7836                 rsurface.batchtvector3f_bufferoffset = 0;
7837                 rsurface.batchnormal3f = NULL;
7838                 rsurface.batchnormal3f_vertexbuffer = NULL;
7839                 rsurface.batchnormal3f_bufferoffset = 0;
7840                 rsurface.batchlightmapcolor4f = NULL;
7841                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7842                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7843                 rsurface.batchtexcoordtexture2f = NULL;
7844                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7845                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7846                 rsurface.batchtexcoordlightmap2f = NULL;
7847                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7848                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7849                 rsurface.batchskeletalindex4ub = NULL;
7850                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7851                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7852                 rsurface.batchskeletalweight4ub = NULL;
7853                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7854                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7855                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7856                 rsurface.batchelement3i_indexbuffer = NULL;
7857                 rsurface.batchelement3i_bufferoffset = 0;
7858                 rsurface.batchelement3s = NULL;
7859                 rsurface.batchelement3s_indexbuffer = NULL;
7860                 rsurface.batchelement3s_bufferoffset = 0;
7861                 rsurface.batchskeletaltransform3x4buffer = NULL;
7862                 rsurface.batchskeletaltransform3x4offset = 0;
7863                 rsurface.batchskeletaltransform3x4size = 0;
7864                 // we'll only be setting up certain arrays as needed
7865                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7866                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7867                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7868                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7869                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7870                 {
7871                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7872                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7873                 }
7874                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7875                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7876                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7877                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7878                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7879                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7880                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7881                 {
7882                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7883                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7884                 }
7885                 numvertices = 0;
7886                 numtriangles = 0;
7887                 for (i = 0;i < texturenumsurfaces;i++)
7888                 {
7889                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7890                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7891                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7892                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7893                         // copy only the data requested
7894                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7895                         {
7896                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7897                                 {
7898                                         if (rsurface.batchvertex3f)
7899                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7900                                         else
7901                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7902                                 }
7903                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7904                                 {
7905                                         if (rsurface.modelnormal3f)
7906                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7907                                         else
7908                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7909                                 }
7910                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7911                                 {
7912                                         if (rsurface.modelsvector3f)
7913                                         {
7914                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7915                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7916                                         }
7917                                         else
7918                                         {
7919                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7920                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7921                                         }
7922                                 }
7923                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7924                                 {
7925                                         if (rsurface.modellightmapcolor4f)
7926                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7927                                         else
7928                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7929                                 }
7930                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7931                                 {
7932                                         if (rsurface.modeltexcoordtexture2f)
7933                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7934                                         else
7935                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7936                                 }
7937                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7938                                 {
7939                                         if (rsurface.modeltexcoordlightmap2f)
7940                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7941                                         else
7942                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7943                                 }
7944                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7945                                 {
7946                                         if (rsurface.modelskeletalindex4ub)
7947                                         {
7948                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7949                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7950                                         }
7951                                         else
7952                                         {
7953                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7954                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7955                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7956                                                 for (j = 0;j < surfacenumvertices;j++)
7957                                                         ub[j*4] = 255;
7958                                         }
7959                                 }
7960                         }
7961                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7962                         numvertices += surfacenumvertices;
7963                         numtriangles += surfacenumtriangles;
7964                 }
7965
7966                 // generate a 16bit index array as well if possible
7967                 // (in general, dynamic batches fit)
7968                 if (numvertices <= 65536)
7969                 {
7970                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7971                         for (i = 0;i < numtriangles*3;i++)
7972                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7973                 }
7974
7975                 // since we've copied everything, the batch now starts at 0
7976                 rsurface.batchfirstvertex = 0;
7977                 rsurface.batchnumvertices = batchnumvertices;
7978                 rsurface.batchfirsttriangle = 0;
7979                 rsurface.batchnumtriangles = batchnumtriangles;
7980         }
7981
7982         // apply skeletal animation that would have been done in the vertex shader
7983         if (rsurface.batchskeletaltransform3x4)
7984         {
7985                 const unsigned char *si;
7986                 const unsigned char *sw;
7987                 const float *t[4];
7988                 const float *b = rsurface.batchskeletaltransform3x4;
7989                 float *vp, *vs, *vt, *vn;
7990                 float w[4];
7991                 float m[3][4], n[3][4];
7992                 float tp[3], ts[3], tt[3], tn[3];
7993                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7994                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7995                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7996                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7997                 si = rsurface.batchskeletalindex4ub;
7998                 sw = rsurface.batchskeletalweight4ub;
7999                 vp = rsurface.batchvertex3f;
8000                 vs = rsurface.batchsvector3f;
8001                 vt = rsurface.batchtvector3f;
8002                 vn = rsurface.batchnormal3f;
8003                 memset(m[0], 0, sizeof(m));
8004                 memset(n[0], 0, sizeof(n));
8005                 for (i = 0;i < batchnumvertices;i++)
8006                 {
8007                         t[0] = b + si[0]*12;
8008                         if (sw[0] == 255)
8009                         {
8010                                 // common case - only one matrix
8011                                 m[0][0] = t[0][ 0];
8012                                 m[0][1] = t[0][ 1];
8013                                 m[0][2] = t[0][ 2];
8014                                 m[0][3] = t[0][ 3];
8015                                 m[1][0] = t[0][ 4];
8016                                 m[1][1] = t[0][ 5];
8017                                 m[1][2] = t[0][ 6];
8018                                 m[1][3] = t[0][ 7];
8019                                 m[2][0] = t[0][ 8];
8020                                 m[2][1] = t[0][ 9];
8021                                 m[2][2] = t[0][10];
8022                                 m[2][3] = t[0][11];
8023                         }
8024                         else if (sw[2] + sw[3])
8025                         {
8026                                 // blend 4 matrices
8027                                 t[1] = b + si[1]*12;
8028                                 t[2] = b + si[2]*12;
8029                                 t[3] = b + si[3]*12;
8030                                 w[0] = sw[0] * (1.0f / 255.0f);
8031                                 w[1] = sw[1] * (1.0f / 255.0f);
8032                                 w[2] = sw[2] * (1.0f / 255.0f);
8033                                 w[3] = sw[3] * (1.0f / 255.0f);
8034                                 // blend the matrices
8035                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8036                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8037                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8038                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8039                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8040                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8041                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8042                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8043                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8044                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8045                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8046                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8047                         }
8048                         else
8049                         {
8050                                 // blend 2 matrices
8051                                 t[1] = b + si[1]*12;
8052                                 w[0] = sw[0] * (1.0f / 255.0f);
8053                                 w[1] = sw[1] * (1.0f / 255.0f);
8054                                 // blend the matrices
8055                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8056                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8057                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8058                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8059                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8060                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8061                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8062                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8063                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8064                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8065                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8066                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8067                         }
8068                         si += 4;
8069                         sw += 4;
8070                         // modify the vertex
8071                         VectorCopy(vp, tp);
8072                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8073                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8074                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8075                         vp += 3;
8076                         if (vn)
8077                         {
8078                                 // the normal transformation matrix is a set of cross products...
8079                                 CrossProduct(m[1], m[2], n[0]);
8080                                 CrossProduct(m[2], m[0], n[1]);
8081                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8082                                 VectorCopy(vn, tn);
8083                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8084                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8085                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8086                                 VectorNormalize(vn);
8087                                 vn += 3;
8088                                 if (vs)
8089                                 {
8090                                         VectorCopy(vs, ts);
8091                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8092                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8093                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8094                                         VectorNormalize(vs);
8095                                         vs += 3;
8096                                         VectorCopy(vt, tt);
8097                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8098                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8099                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8100                                         VectorNormalize(vt);
8101                                         vt += 3;
8102                                 }
8103                         }
8104                 }
8105                 rsurface.batchskeletaltransform3x4 = NULL;
8106                 rsurface.batchskeletalnumtransforms = 0;
8107         }
8108
8109         // q1bsp surfaces rendered in vertex color mode have to have colors
8110         // calculated based on lightstyles
8111         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8112         {
8113                 // generate color arrays for the surfaces in this list
8114                 int c[4];
8115                 int scale;
8116                 int size3;
8117                 const int *offsets;
8118                 const unsigned char *lm;
8119                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8120                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8121                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8122                 numvertices = 0;
8123                 for (i = 0;i < texturenumsurfaces;i++)
8124                 {
8125                         surface = texturesurfacelist[i];
8126                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8127                         surfacenumvertices = surface->num_vertices;
8128                         if (surface->lightmapinfo->samples)
8129                         {
8130                                 for (j = 0;j < surfacenumvertices;j++)
8131                                 {
8132                                         lm = surface->lightmapinfo->samples + offsets[j];
8133                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8134                                         VectorScale(lm, scale, c);
8135                                         if (surface->lightmapinfo->styles[1] != 255)
8136                                         {
8137                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8138                                                 lm += size3;
8139                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8140                                                 VectorMA(c, scale, lm, c);
8141                                                 if (surface->lightmapinfo->styles[2] != 255)
8142                                                 {
8143                                                         lm += size3;
8144                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8145                                                         VectorMA(c, scale, lm, c);
8146                                                         if (surface->lightmapinfo->styles[3] != 255)
8147                                                         {
8148                                                                 lm += size3;
8149                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8150                                                                 VectorMA(c, scale, lm, c);
8151                                                         }
8152                                                 }
8153                                         }
8154                                         c[0] >>= 7;
8155                                         c[1] >>= 7;
8156                                         c[2] >>= 7;
8157                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, min(c[0], 255) * (1.0f / 255.0f), min(c[1], 255) * (1.0f / 255.0f), min(c[2], 255) * (1.0f / 255.0f), 1);
8158                                         numvertices++;
8159                                 }
8160                         }
8161                         else
8162                         {
8163                                 for (j = 0;j < surfacenumvertices;j++)
8164                                 {
8165                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8166                                         numvertices++;
8167                                 }
8168                         }
8169                 }
8170         }
8171
8172         // if vertices are deformed (sprite flares and things in maps, possibly
8173         // water waves, bulges and other deformations), modify the copied vertices
8174         // in place
8175         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8176         {
8177                 float scale;
8178                 switch (deform->deform)
8179                 {
8180                 default:
8181                 case Q3DEFORM_PROJECTIONSHADOW:
8182                 case Q3DEFORM_TEXT0:
8183                 case Q3DEFORM_TEXT1:
8184                 case Q3DEFORM_TEXT2:
8185                 case Q3DEFORM_TEXT3:
8186                 case Q3DEFORM_TEXT4:
8187                 case Q3DEFORM_TEXT5:
8188                 case Q3DEFORM_TEXT6:
8189                 case Q3DEFORM_TEXT7:
8190                 case Q3DEFORM_NONE:
8191                         break;
8192                 case Q3DEFORM_AUTOSPRITE:
8193                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8194                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8195                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8196                         VectorNormalize(newforward);
8197                         VectorNormalize(newright);
8198                         VectorNormalize(newup);
8199 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8200 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8201 //                      rsurface.batchvertex3f_bufferoffset = 0;
8202 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8203 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8204 //                      rsurface.batchsvector3f_bufferoffset = 0;
8205 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8206 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8207 //                      rsurface.batchtvector3f_bufferoffset = 0;
8208 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8209 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8210 //                      rsurface.batchnormal3f_bufferoffset = 0;
8211                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8212                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8213                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8214                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8215                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8216                         // a single autosprite surface can contain multiple sprites...
8217                         for (j = 0;j < batchnumvertices - 3;j += 4)
8218                         {
8219                                 VectorClear(center);
8220                                 for (i = 0;i < 4;i++)
8221                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8222                                 VectorScale(center, 0.25f, center);
8223                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8224                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8225                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8226                                 for (i = 0;i < 4;i++)
8227                                 {
8228                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8229                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8230                                 }
8231                         }
8232                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8233                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8234                         Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8235                         break;
8236                 case Q3DEFORM_AUTOSPRITE2:
8237                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8238                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8239                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8240                         VectorNormalize(newforward);
8241                         VectorNormalize(newright);
8242                         VectorNormalize(newup);
8243 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8244 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8245 //                      rsurface.batchvertex3f_bufferoffset = 0;
8246                         {
8247                                 const float *v1, *v2;
8248                                 vec3_t start, end;
8249                                 float f, l;
8250                                 struct
8251                                 {
8252                                         float length2;
8253                                         const float *v1;
8254                                         const float *v2;
8255                                 }
8256                                 shortest[2];
8257                                 memset(shortest, 0, sizeof(shortest));
8258                                 // a single autosprite surface can contain multiple sprites...
8259                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8260                                 {
8261                                         VectorClear(center);
8262                                         for (i = 0;i < 4;i++)
8263                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8264                                         VectorScale(center, 0.25f, center);
8265                                         // find the two shortest edges, then use them to define the
8266                                         // axis vectors for rotating around the central axis
8267                                         for (i = 0;i < 6;i++)
8268                                         {
8269                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8270                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8271                                                 l = VectorDistance2(v1, v2);
8272                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8273                                                 if (v1[2] != v2[2])
8274                                                         l += (1.0f / 1024.0f);
8275                                                 if (shortest[0].length2 > l || i == 0)
8276                                                 {
8277                                                         shortest[1] = shortest[0];
8278                                                         shortest[0].length2 = l;
8279                                                         shortest[0].v1 = v1;
8280                                                         shortest[0].v2 = v2;
8281                                                 }
8282                                                 else if (shortest[1].length2 > l || i == 1)
8283                                                 {
8284                                                         shortest[1].length2 = l;
8285                                                         shortest[1].v1 = v1;
8286                                                         shortest[1].v2 = v2;
8287                                                 }
8288                                         }
8289                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8290                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8291                                         // this calculates the right vector from the shortest edge
8292                                         // and the up vector from the edge midpoints
8293                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8294                                         VectorNormalize(right);
8295                                         VectorSubtract(end, start, up);
8296                                         VectorNormalize(up);
8297                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8298                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8299                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8300                                         VectorNegate(forward, forward);
8301                                         VectorReflect(forward, 0, up, forward);
8302                                         VectorNormalize(forward);
8303                                         CrossProduct(up, forward, newright);
8304                                         VectorNormalize(newright);
8305                                         // rotate the quad around the up axis vector, this is made
8306                                         // especially easy by the fact we know the quad is flat,
8307                                         // so we only have to subtract the center position and
8308                                         // measure distance along the right vector, and then
8309                                         // multiply that by the newright vector and add back the
8310                                         // center position
8311                                         // we also need to subtract the old position to undo the
8312                                         // displacement from the center, which we do with a
8313                                         // DotProduct, the subtraction/addition of center is also
8314                                         // optimized into DotProducts here
8315                                         l = DotProduct(right, center);
8316                                         for (i = 0;i < 4;i++)
8317                                         {
8318                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8319                                                 f = DotProduct(right, v1) - l;
8320                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8321                                         }
8322                                 }
8323                         }
8324                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8325                         {
8326 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8327 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8328 //                              rsurface.batchnormal3f_bufferoffset = 0;
8329                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8330                         }
8331                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8332                         {
8333 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8334 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8335 //                              rsurface.batchsvector3f_bufferoffset = 0;
8336 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8337 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8338 //                              rsurface.batchtvector3f_bufferoffset = 0;
8339                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8340                         }
8341                         break;
8342                 case Q3DEFORM_NORMAL:
8343                         // deform the normals to make reflections wavey
8344                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8345                         rsurface.batchnormal3f_vertexbuffer = NULL;
8346                         rsurface.batchnormal3f_bufferoffset = 0;
8347                         for (j = 0;j < batchnumvertices;j++)
8348                         {
8349                                 float vertex[3];
8350                                 float *normal = rsurface.batchnormal3f + 3*j;
8351                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8352                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8353                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8354                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8355                                 VectorNormalize(normal);
8356                         }
8357                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8358                         {
8359 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8360 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8361 //                              rsurface.batchsvector3f_bufferoffset = 0;
8362 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8363 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8364 //                              rsurface.batchtvector3f_bufferoffset = 0;
8365                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8366                         }
8367                         break;
8368                 case Q3DEFORM_WAVE:
8369                         // deform vertex array to make wavey water and flags and such
8370                         waveparms[0] = deform->waveparms[0];
8371                         waveparms[1] = deform->waveparms[1];
8372                         waveparms[2] = deform->waveparms[2];
8373                         waveparms[3] = deform->waveparms[3];
8374                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8375                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8376                         // this is how a divisor of vertex influence on deformation
8377                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8378                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8379 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8380 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8381 //                      rsurface.batchvertex3f_bufferoffset = 0;
8382 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8383 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8384 //                      rsurface.batchnormal3f_bufferoffset = 0;
8385                         for (j = 0;j < batchnumvertices;j++)
8386                         {
8387                                 // if the wavefunc depends on time, evaluate it per-vertex
8388                                 if (waveparms[3])
8389                                 {
8390                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8391                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8392                                 }
8393                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8394                         }
8395                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8396                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8397                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8398                         {
8399 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8400 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8401 //                              rsurface.batchsvector3f_bufferoffset = 0;
8402 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8403 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8404 //                              rsurface.batchtvector3f_bufferoffset = 0;
8405                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8406                         }
8407                         break;
8408                 case Q3DEFORM_BULGE:
8409                         // deform vertex array to make the surface have moving bulges
8410 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8411 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8412 //                      rsurface.batchvertex3f_bufferoffset = 0;
8413 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8414 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8415 //                      rsurface.batchnormal3f_bufferoffset = 0;
8416                         for (j = 0;j < batchnumvertices;j++)
8417                         {
8418                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8419                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8420                         }
8421                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8422                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8423                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8424                         {
8425 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8426 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8427 //                              rsurface.batchsvector3f_bufferoffset = 0;
8428 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8429 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8430 //                              rsurface.batchtvector3f_bufferoffset = 0;
8431                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8432                         }
8433                         break;
8434                 case Q3DEFORM_MOVE:
8435                         // deform vertex array
8436                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8437                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8438                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8439                         VectorScale(deform->parms, scale, waveparms);
8440 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8441 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8442 //                      rsurface.batchvertex3f_bufferoffset = 0;
8443                         for (j = 0;j < batchnumvertices;j++)
8444                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8445                         break;
8446                 }
8447         }
8448
8449         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8450         {
8451         // generate texcoords based on the chosen texcoord source
8452                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8453                 {
8454                 default:
8455                 case Q3TCGEN_TEXTURE:
8456                         break;
8457                 case Q3TCGEN_LIGHTMAP:
8458         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8459         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8460         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8461                         if (rsurface.batchtexcoordlightmap2f)
8462                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8463                         break;
8464                 case Q3TCGEN_VECTOR:
8465         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8466         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8467         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8468                         for (j = 0;j < batchnumvertices;j++)
8469                         {
8470                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8471                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8472                         }
8473                         break;
8474                 case Q3TCGEN_ENVIRONMENT:
8475                         // make environment reflections using a spheremap
8476                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8477                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8478                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8479                         for (j = 0;j < batchnumvertices;j++)
8480                         {
8481                                 // identical to Q3A's method, but executed in worldspace so
8482                                 // carried models can be shiny too
8483
8484                                 float viewer[3], d, reflected[3], worldreflected[3];
8485
8486                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8487                                 // VectorNormalize(viewer);
8488
8489                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8490
8491                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8492                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8493                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8494                                 // note: this is proportinal to viewer, so we can normalize later
8495
8496                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8497                                 VectorNormalize(worldreflected);
8498
8499                                 // note: this sphere map only uses world x and z!
8500                                 // so positive and negative y will LOOK THE SAME.
8501                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8502                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8503                         }
8504                         break;
8505                 }
8506                 // the only tcmod that needs software vertex processing is turbulent, so
8507                 // check for it here and apply the changes if needed
8508                 // and we only support that as the first one
8509                 // (handling a mixture of turbulent and other tcmods would be problematic
8510                 //  without punting it entirely to a software path)
8511                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8512                 {
8513                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8514                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8515         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8516         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8517         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8518                         for (j = 0;j < batchnumvertices;j++)
8519                         {
8520                                 rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8521                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8522                         }
8523                 }
8524         }
8525 }
8526
8527 void RSurf_DrawBatch(void)
8528 {
8529         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8530         // through the pipeline, killing it earlier in the pipeline would have
8531         // per-surface overhead rather than per-batch overhead, so it's best to
8532         // reject it here, before it hits glDraw.
8533         if (rsurface.batchnumtriangles == 0)
8534                 return;
8535 #if 0
8536         // batch debugging code
8537         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8538         {
8539                 int i;
8540                 int j;
8541                 int c;
8542                 const int *e;
8543                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8544                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8545                 {
8546                         c = e[i];
8547                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8548                         {
8549                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8550                                 {
8551                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8552                                                 Sys_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);
8553                                         break;
8554                                 }
8555                         }
8556                 }
8557         }
8558 #endif
8559         if (rsurface.batchmultidraw)
8560         {
8561                 // issue multiple draws rather than copying index data
8562                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8563                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8564                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8565                 for (i = 0;i < numsurfaces;)
8566                 {
8567                         // combine consecutive surfaces as one draw
8568                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8569                                 if (surfacelist[j] != surfacelist[k] + 1)
8570                                         break;
8571                         firstvertex = surfacelist[i]->num_firstvertex;
8572                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8573                         firsttriangle = surfacelist[i]->num_firsttriangle;
8574                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8575                         R_Mesh_Draw(firstvertex, endvertex - firstvertex, firsttriangle, endtriangle - firsttriangle, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
8576                         i = j;
8577                 }
8578         }
8579         else
8580         {
8581                 // there is only one consecutive run of index data (may have been combined)
8582                 R_Mesh_Draw(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchfirsttriangle, rsurface.batchnumtriangles, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
8583         }
8584 }
8585
8586 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8587 {
8588         // pick the closest matching water plane
8589         int planeindex, vertexindex, bestplaneindex = -1;
8590         float d, bestd;
8591         vec3_t vert;
8592         const float *v;
8593         r_waterstate_waterplane_t *p;
8594         qbool prepared = false;
8595         bestd = 0;
8596         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8597         {
8598                 if(p->camera_entity != rsurface.texture->camera_entity)
8599                         continue;
8600                 d = 0;
8601                 if(!prepared)
8602                 {
8603                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8604                         prepared = true;
8605                         if(rsurface.batchnumvertices == 0)
8606                                 break;
8607                 }
8608                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8609                 {
8610                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8611                         d += fabs(PlaneDiff(vert, &p->plane));
8612                 }
8613                 if (bestd > d || bestplaneindex < 0)
8614                 {
8615                         bestd = d;
8616                         bestplaneindex = planeindex;
8617                 }
8618         }
8619         return bestplaneindex;
8620         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8621         // this situation though, as it might be better to render single larger
8622         // batches with useless stuff (backface culled for example) than to
8623         // render multiple smaller batches
8624 }
8625
8626 void RSurf_SetupDepthAndCulling(void)
8627 {
8628         // submodels are biased to avoid z-fighting with world surfaces that they
8629         // may be exactly overlapping (avoids z-fighting artifacts on certain
8630         // doors and things in Quake maps)
8631         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8632         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8633         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8634         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8635 }
8636
8637 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8638 {
8639         int j;
8640         const float *v;
8641         float p[3], mins[3], maxs[3];
8642         int scissor[4];
8643         // transparent sky would be ridiculous
8644         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8645                 return;
8646         R_SetupShader_Generic_NoTexture(false, false);
8647         skyrenderlater = true;
8648         RSurf_SetupDepthAndCulling();
8649         GL_DepthMask(true);
8650
8651         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8652         if (r_sky_scissor.integer)
8653         {
8654                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8655                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8656                 {
8657                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8658                         if (j > 0)
8659                         {
8660                                 if (mins[0] > p[0]) mins[0] = p[0];
8661                                 if (mins[1] > p[1]) mins[1] = p[1];
8662                                 if (mins[2] > p[2]) mins[2] = p[2];
8663                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8664                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8665                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8666                         }
8667                         else
8668                         {
8669                                 VectorCopy(p, mins);
8670                                 VectorCopy(p, maxs);
8671                         }
8672                 }
8673                 if (!R_ScissorForBBox(mins, maxs, scissor))
8674                 {
8675                         if (skyscissor[2])
8676                         {
8677                                 if (skyscissor[0] > scissor[0])
8678                                 {
8679                                         skyscissor[2] += skyscissor[0] - scissor[0];
8680                                         skyscissor[0] = scissor[0];
8681                                 }
8682                                 if (skyscissor[1] > scissor[1])
8683                                 {
8684                                         skyscissor[3] += skyscissor[1] - scissor[1];
8685                                         skyscissor[1] = scissor[1];
8686                                 }
8687                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8688                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8689                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8690                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8691                         }
8692                         else
8693                                 Vector4Copy(scissor, skyscissor);
8694                 }
8695         }
8696
8697         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8698         // skymasking on them, and Quake3 never did sky masking (unlike
8699         // software Quake and software Quake2), so disable the sky masking
8700         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8701         // and skymasking also looks very bad when noclipping outside the
8702         // level, so don't use it then either.
8703         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.skymasking && (r_refdef.scene.worldmodel->brush.isq3bsp ? r_q3bsp_renderskydepth.integer : r_q1bsp_skymasking.integer) && !r_refdef.viewcache.world_novis && !r_trippy.integer)
8704         {
8705                 R_Mesh_ResetTextureState();
8706                 if (skyrendermasked)
8707                 {
8708                         R_SetupShader_DepthOrShadow(false, false, false);
8709                         // depth-only (masking)
8710                         GL_ColorMask(0, 0, 0, 0);
8711                         // just to make sure that braindead drivers don't draw
8712                         // anything despite that colormask...
8713                         GL_BlendFunc(GL_ZERO, GL_ONE);
8714                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8715                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8716                 }
8717                 else
8718                 {
8719                         R_SetupShader_Generic_NoTexture(false, false);
8720                         // fog sky
8721                         GL_BlendFunc(GL_ONE, GL_ZERO);
8722                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8723                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8724                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8725                 }
8726                 RSurf_DrawBatch();
8727                 if (skyrendermasked)
8728                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8729         }
8730         R_Mesh_ResetTextureState();
8731         GL_Color(1, 1, 1, 1);
8732 }
8733
8734 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8735 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8736 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8737 {
8738         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8739                 return;
8740         if (prepass)
8741         {
8742                 // render screenspace normalmap to texture
8743                 GL_DepthMask(true);
8744                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8745                 RSurf_DrawBatch();
8746                 return;
8747         }
8748
8749         // bind lightmap texture
8750
8751         // water/refraction/reflection/camera surfaces have to be handled specially
8752         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8753         {
8754                 int start, end, startplaneindex;
8755                 for (start = 0;start < texturenumsurfaces;start = end)
8756                 {
8757                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8758                         if(startplaneindex < 0)
8759                         {
8760                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8761                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8762                                 end = start + 1;
8763                                 continue;
8764                         }
8765                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8766                                 ;
8767                         // now that we have a batch using the same planeindex, render it
8768                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8769                         {
8770                                 // render water or distortion background
8771                                 GL_DepthMask(true);
8772                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8773                                 RSurf_DrawBatch();
8774                                 // blend surface on top
8775                                 GL_DepthMask(false);
8776                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8777                                 RSurf_DrawBatch();
8778                         }
8779                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8780                         {
8781                                 // render surface with reflection texture as input
8782                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8783                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8784                                 RSurf_DrawBatch();
8785                         }
8786                 }
8787                 return;
8788         }
8789
8790         // render surface batch normally
8791         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8792         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8793         RSurf_DrawBatch();
8794 }
8795
8796 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8797 {
8798         int vi;
8799         int j;
8800         int texturesurfaceindex;
8801         int k;
8802         const msurface_t *surface;
8803         float surfacecolor4f[4];
8804
8805 //      R_Mesh_ResetTextureState();
8806         R_SetupShader_Generic_NoTexture(false, false);
8807
8808         GL_BlendFunc(GL_ONE, GL_ZERO);
8809         GL_DepthMask(writedepth);
8810
8811         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8812         vi = 0;
8813         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8814         {
8815                 surface = texturesurfacelist[texturesurfaceindex];
8816                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8817                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8818                 for (j = 0;j < surface->num_vertices;j++)
8819                 {
8820                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8821                         vi++;
8822                 }
8823         }
8824         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8825         RSurf_DrawBatch();
8826 }
8827
8828 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8829 {
8830         CHECKGLERROR
8831         RSurf_SetupDepthAndCulling();
8832         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8833         {
8834                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8835                 return;
8836         }
8837         switch (vid.renderpath)
8838         {
8839         case RENDERPATH_GL32:
8840         case RENDERPATH_GLES2:
8841                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8842                 break;
8843         }
8844         CHECKGLERROR
8845 }
8846
8847 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8848 {
8849         int i, j;
8850         int texturenumsurfaces, endsurface;
8851         texture_t *texture;
8852         const msurface_t *surface;
8853         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8854
8855         RSurf_ActiveModelEntity(ent, true, true, false);
8856
8857         if (r_transparentdepthmasking.integer)
8858         {
8859                 qbool setup = false;
8860                 for (i = 0;i < numsurfaces;i = j)
8861                 {
8862                         j = i + 1;
8863                         surface = rsurface.modelsurfaces + surfacelist[i];
8864                         texture = surface->texture;
8865                         rsurface.texture = R_GetCurrentTexture(texture);
8866                         rsurface.lightmaptexture = NULL;
8867                         rsurface.deluxemaptexture = NULL;
8868                         rsurface.uselightmaptexture = false;
8869                         // scan ahead until we find a different texture
8870                         endsurface = min(i + 1024, numsurfaces);
8871                         texturenumsurfaces = 0;
8872                         texturesurfacelist[texturenumsurfaces++] = surface;
8873                         for (;j < endsurface;j++)
8874                         {
8875                                 surface = rsurface.modelsurfaces + surfacelist[j];
8876                                 if (texture != surface->texture)
8877                                         break;
8878                                 texturesurfacelist[texturenumsurfaces++] = surface;
8879                         }
8880                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8881                                 continue;
8882                         // render the range of surfaces as depth
8883                         if (!setup)
8884                         {
8885                                 setup = true;
8886                                 GL_ColorMask(0,0,0,0);
8887                                 GL_Color(1,1,1,1);
8888                                 GL_DepthTest(true);
8889                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8890                                 GL_DepthMask(true);
8891 //                              R_Mesh_ResetTextureState();
8892                         }
8893                         RSurf_SetupDepthAndCulling();
8894                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8895                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8896                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8897                         RSurf_DrawBatch();
8898                 }
8899                 if (setup)
8900                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8901         }
8902
8903         for (i = 0;i < numsurfaces;i = j)
8904         {
8905                 j = i + 1;
8906                 surface = rsurface.modelsurfaces + surfacelist[i];
8907                 texture = surface->texture;
8908                 rsurface.texture = R_GetCurrentTexture(texture);
8909                 // scan ahead until we find a different texture
8910                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8911                 texturenumsurfaces = 0;
8912                 texturesurfacelist[texturenumsurfaces++] = surface;
8913                         rsurface.lightmaptexture = surface->lightmaptexture;
8914                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8915                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8916                         for (;j < endsurface;j++)
8917                         {
8918                                 surface = rsurface.modelsurfaces + surfacelist[j];
8919                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8920                                         break;
8921                                 texturesurfacelist[texturenumsurfaces++] = surface;
8922                         }
8923                 // render the range of surfaces
8924                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8925         }
8926         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8927 }
8928
8929 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8930 {
8931         // transparent surfaces get pushed off into the transparent queue
8932         int surfacelistindex;
8933         const msurface_t *surface;
8934         vec3_t tempcenter, center;
8935         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8936         {
8937                 surface = texturesurfacelist[surfacelistindex];
8938                 if (r_transparent_sortsurfacesbynearest.integer)
8939                 {
8940                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8941                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8942                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8943                 }
8944                 else
8945                 {
8946                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8947                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8948                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8949                 }
8950                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8951                 if (rsurface.entity->transparent_offset) // transparent offset
8952                 {
8953                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8954                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8955                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8956                 }
8957                 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);
8958         }
8959 }
8960
8961 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8962 {
8963         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8964                 return;
8965         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8966                 return;
8967         RSurf_SetupDepthAndCulling();
8968         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8969         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8970         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8971         RSurf_DrawBatch();
8972 }
8973
8974 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8975 {
8976         CHECKGLERROR
8977         if (ui)
8978                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8979         else if (depthonly)
8980                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8981         else if (prepass)
8982         {
8983                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8984                         return;
8985                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8986                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8987                 else
8988                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8989         }
8990         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8991                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8992         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8993                 return;
8994         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8995         {
8996                 // in the deferred case, transparent surfaces were queued during prepass
8997                 if (!r_shadow_usingdeferredprepass)
8998                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8999         }
9000         else
9001         {
9002                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9003                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9004         }
9005         CHECKGLERROR
9006 }
9007
9008 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9009 {
9010         int i, j;
9011         texture_t *texture;
9012         R_FrameData_SetMark();
9013         // break the surface list down into batches by texture and use of lightmapping
9014         for (i = 0;i < numsurfaces;i = j)
9015         {
9016                 j = i + 1;
9017                 // texture is the base texture pointer, rsurface.texture is the
9018                 // current frame/skin the texture is directing us to use (for example
9019                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9020                 // use skin 1 instead)
9021                 texture = surfacelist[i]->texture;
9022                 rsurface.texture = R_GetCurrentTexture(texture);
9023                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9024                 {
9025                         // if this texture is not the kind we want, skip ahead to the next one
9026                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9027                                 ;
9028                         continue;
9029                 }
9030                 if(depthonly || prepass)
9031                 {
9032                         rsurface.lightmaptexture = NULL;
9033                         rsurface.deluxemaptexture = NULL;
9034                         rsurface.uselightmaptexture = false;
9035                         // simply scan ahead until we find a different texture or lightmap state
9036                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9037                                 ;
9038                 }
9039                 else
9040                 {
9041                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9042                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9043                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9044                         // simply scan ahead until we find a different texture or lightmap state
9045                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9046                                 ;
9047                 }
9048                 // render the range of surfaces
9049                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9050         }
9051         R_FrameData_ReturnToMark();
9052 }
9053
9054 float locboxvertex3f[6*4*3] =
9055 {
9056         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9057         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9058         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9059         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9060         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9061         1,0,0, 0,0,0, 0,1,0, 1,1,0
9062 };
9063
9064 unsigned short locboxelements[6*2*3] =
9065 {
9066          0, 1, 2, 0, 2, 3,
9067          4, 5, 6, 4, 6, 7,
9068          8, 9,10, 8,10,11,
9069         12,13,14, 12,14,15,
9070         16,17,18, 16,18,19,
9071         20,21,22, 20,22,23
9072 };
9073
9074 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9075 {
9076         int i, j;
9077         cl_locnode_t *loc = (cl_locnode_t *)ent;
9078         vec3_t mins, size;
9079         float vertex3f[6*4*3];
9080         CHECKGLERROR
9081         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9082         GL_DepthMask(false);
9083         GL_DepthRange(0, 1);
9084         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9085         GL_DepthTest(true);
9086         GL_CullFace(GL_NONE);
9087         R_EntityMatrix(&identitymatrix);
9088
9089 //      R_Mesh_ResetTextureState();
9090
9091         i = surfacelist[0];
9092         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9093                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9094                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9095                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9096
9097         if (VectorCompare(loc->mins, loc->maxs))
9098         {
9099                 VectorSet(size, 2, 2, 2);
9100                 VectorMA(loc->mins, -0.5f, size, mins);
9101         }
9102         else
9103         {
9104                 VectorCopy(loc->mins, mins);
9105                 VectorSubtract(loc->maxs, loc->mins, size);
9106         }
9107
9108         for (i = 0;i < 6*4*3;)
9109                 for (j = 0;j < 3;j++, i++)
9110                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9111
9112         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9113         R_SetupShader_Generic_NoTexture(false, false);
9114         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9115 }
9116
9117 void R_DrawLocs(void)
9118 {
9119         int index;
9120         cl_locnode_t *loc, *nearestloc;
9121         vec3_t center;
9122         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9123         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9124         {
9125                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9126                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9127         }
9128 }
9129
9130 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9131 {
9132         if (decalsystem->decals)
9133                 Mem_Free(decalsystem->decals);
9134         memset(decalsystem, 0, sizeof(*decalsystem));
9135 }
9136
9137 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)
9138 {
9139         tridecal_t *decal;
9140         tridecal_t *decals;
9141         int i;
9142
9143         // expand or initialize the system
9144         if (decalsystem->maxdecals <= decalsystem->numdecals)
9145         {
9146                 decalsystem_t old = *decalsystem;
9147                 qbool useshortelements;
9148                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9149                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9150                 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)));
9151                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9152                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9153                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9154                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9155                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9156                 if (decalsystem->numdecals)
9157                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9158                 if (old.decals)
9159                         Mem_Free(old.decals);
9160                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9161                         decalsystem->element3i[i] = i;
9162                 if (useshortelements)
9163                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9164                                 decalsystem->element3s[i] = i;
9165         }
9166
9167         // grab a decal and search for another free slot for the next one
9168         decals = decalsystem->decals;
9169         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9170         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9171                 ;
9172         decalsystem->freedecal = i;
9173         if (decalsystem->numdecals <= i)
9174                 decalsystem->numdecals = i + 1;
9175
9176         // initialize the decal
9177         decal->lived = 0;
9178         decal->triangleindex = triangleindex;
9179         decal->surfaceindex = surfaceindex;
9180         decal->decalsequence = decalsequence;
9181         decal->color4f[0][0] = c0[0];
9182         decal->color4f[0][1] = c0[1];
9183         decal->color4f[0][2] = c0[2];
9184         decal->color4f[0][3] = 1;
9185         decal->color4f[1][0] = c1[0];
9186         decal->color4f[1][1] = c1[1];
9187         decal->color4f[1][2] = c1[2];
9188         decal->color4f[1][3] = 1;
9189         decal->color4f[2][0] = c2[0];
9190         decal->color4f[2][1] = c2[1];
9191         decal->color4f[2][2] = c2[2];
9192         decal->color4f[2][3] = 1;
9193         decal->vertex3f[0][0] = v0[0];
9194         decal->vertex3f[0][1] = v0[1];
9195         decal->vertex3f[0][2] = v0[2];
9196         decal->vertex3f[1][0] = v1[0];
9197         decal->vertex3f[1][1] = v1[1];
9198         decal->vertex3f[1][2] = v1[2];
9199         decal->vertex3f[2][0] = v2[0];
9200         decal->vertex3f[2][1] = v2[1];
9201         decal->vertex3f[2][2] = v2[2];
9202         decal->texcoord2f[0][0] = t0[0];
9203         decal->texcoord2f[0][1] = t0[1];
9204         decal->texcoord2f[1][0] = t1[0];
9205         decal->texcoord2f[1][1] = t1[1];
9206         decal->texcoord2f[2][0] = t2[0];
9207         decal->texcoord2f[2][1] = t2[1];
9208         TriangleNormal(v0, v1, v2, decal->plane);
9209         VectorNormalize(decal->plane);
9210         decal->plane[3] = DotProduct(v0, decal->plane);
9211 }
9212
9213 extern cvar_t cl_decals_bias;
9214 extern cvar_t cl_decals_models;
9215 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9216 // baseparms, parms, temps
9217 static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qbool dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9218 {
9219         int cornerindex;
9220         int index;
9221         float v[9][3];
9222         const float *vertex3f;
9223         const float *normal3f;
9224         int numpoints;
9225         float points[2][9][3];
9226         float temp[3];
9227         float tc[9][2];
9228         float f;
9229         float c[9][4];
9230         const int *e;
9231
9232         e = rsurface.modelelement3i + 3*triangleindex;
9233
9234         vertex3f = rsurface.modelvertex3f;
9235         normal3f = rsurface.modelnormal3f;
9236
9237         if (normal3f)
9238         {
9239                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9240                 {
9241                         index = 3*e[cornerindex];
9242                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9243                 }
9244         }
9245         else
9246         {
9247                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9248                 {
9249                         index = 3*e[cornerindex];
9250                         VectorCopy(vertex3f + index, v[cornerindex]);
9251                 }
9252         }
9253
9254         // cull backfaces
9255         //TriangleNormal(v[0], v[1], v[2], normal);
9256         //if (DotProduct(normal, localnormal) < 0.0f)
9257         //      continue;
9258         // clip by each of the box planes formed from the projection matrix
9259         // if anything survives, we emit the decal
9260         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]);
9261         if (numpoints < 3)
9262                 return;
9263         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]);
9264         if (numpoints < 3)
9265                 return;
9266         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]);
9267         if (numpoints < 3)
9268                 return;
9269         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]);
9270         if (numpoints < 3)
9271                 return;
9272         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]);
9273         if (numpoints < 3)
9274                 return;
9275         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]);
9276         if (numpoints < 3)
9277                 return;
9278         // some part of the triangle survived, so we have to accept it...
9279         if (dynamic)
9280         {
9281                 // dynamic always uses the original triangle
9282                 numpoints = 3;
9283                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9284                 {
9285                         index = 3*e[cornerindex];
9286                         VectorCopy(vertex3f + index, v[cornerindex]);
9287                 }
9288         }
9289         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9290         {
9291                 // convert vertex positions to texcoords
9292                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9293                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9294                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9295                 // calculate distance fade from the projection origin
9296                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9297                 f = bound(0.0f, f, 1.0f);
9298                 c[cornerindex][0] = r * f;
9299                 c[cornerindex][1] = g * f;
9300                 c[cornerindex][2] = b * f;
9301                 c[cornerindex][3] = 1.0f;
9302                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9303         }
9304         if (dynamic)
9305                 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);
9306         else
9307                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9308                         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);
9309 }
9310 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)
9311 {
9312         matrix4x4_t projection;
9313         decalsystem_t *decalsystem;
9314         qbool dynamic;
9315         model_t *model;
9316         const msurface_t *surface;
9317         const msurface_t *surfaces;
9318         const int *surfacelist;
9319         const texture_t *texture;
9320         int numtriangles;
9321         int numsurfacelist;
9322         int surfacelistindex;
9323         int surfaceindex;
9324         int triangleindex;
9325         float localorigin[3];
9326         float localnormal[3];
9327         float localmins[3];
9328         float localmaxs[3];
9329         float localsize;
9330         //float normal[3];
9331         float planes[6][4];
9332         float angles[3];
9333         bih_t *bih;
9334         int bih_triangles_count;
9335         int bih_triangles[256];
9336         int bih_surfaces[256];
9337
9338         decalsystem = &ent->decalsystem;
9339         model = ent->model;
9340         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9341         {
9342                 R_DecalSystem_Reset(&ent->decalsystem);
9343                 return;
9344         }
9345
9346         if (!model->brush.data_leafs && !cl_decals_models.integer)
9347         {
9348                 if (decalsystem->model)
9349                         R_DecalSystem_Reset(decalsystem);
9350                 return;
9351         }
9352
9353         if (decalsystem->model != model)
9354                 R_DecalSystem_Reset(decalsystem);
9355         decalsystem->model = model;
9356
9357         RSurf_ActiveModelEntity(ent, true, false, false);
9358
9359         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9360         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9361         VectorNormalize(localnormal);
9362         localsize = worldsize*rsurface.inversematrixscale;
9363         localmins[0] = localorigin[0] - localsize;
9364         localmins[1] = localorigin[1] - localsize;
9365         localmins[2] = localorigin[2] - localsize;
9366         localmaxs[0] = localorigin[0] + localsize;
9367         localmaxs[1] = localorigin[1] + localsize;
9368         localmaxs[2] = localorigin[2] + localsize;
9369
9370         //VectorCopy(localnormal, planes[4]);
9371         //VectorVectors(planes[4], planes[2], planes[0]);
9372         AnglesFromVectors(angles, localnormal, NULL, false);
9373         AngleVectors(angles, planes[0], planes[2], planes[4]);
9374         VectorNegate(planes[0], planes[1]);
9375         VectorNegate(planes[2], planes[3]);
9376         VectorNegate(planes[4], planes[5]);
9377         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9378         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9379         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9380         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9381         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9382         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9383
9384 #if 1
9385 // works
9386 {
9387         matrix4x4_t forwardprojection;
9388         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9389         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9390 }
9391 #else
9392 // broken
9393 {
9394         float projectionvector[4][3];
9395         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9396         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9397         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9398         projectionvector[0][0] = planes[0][0] * ilocalsize;
9399         projectionvector[0][1] = planes[1][0] * ilocalsize;
9400         projectionvector[0][2] = planes[2][0] * ilocalsize;
9401         projectionvector[1][0] = planes[0][1] * ilocalsize;
9402         projectionvector[1][1] = planes[1][1] * ilocalsize;
9403         projectionvector[1][2] = planes[2][1] * ilocalsize;
9404         projectionvector[2][0] = planes[0][2] * ilocalsize;
9405         projectionvector[2][1] = planes[1][2] * ilocalsize;
9406         projectionvector[2][2] = planes[2][2] * ilocalsize;
9407         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9408         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9409         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9410         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9411 }
9412 #endif
9413
9414         dynamic = model->surfmesh.isanimated;
9415         numsurfacelist = model->nummodelsurfaces;
9416         surfacelist = model->sortedmodelsurfaces;
9417         surfaces = model->data_surfaces;
9418
9419         bih = NULL;
9420         bih_triangles_count = -1;
9421         if(!dynamic)
9422         {
9423                 if(model->render_bih.numleafs)
9424                         bih = &model->render_bih;
9425                 else if(model->collision_bih.numleafs)
9426                         bih = &model->collision_bih;
9427         }
9428         if(bih)
9429                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9430         if(bih_triangles_count == 0)
9431                 return;
9432         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9433                 return;
9434         if(bih_triangles_count > 0)
9435         {
9436                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9437                 {
9438                         surfaceindex = bih_surfaces[triangleindex];
9439                         surface = surfaces + surfaceindex;
9440                         texture = surface->texture;
9441                         if (!texture)
9442                                 continue;
9443                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9444                                 continue;
9445                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9446                                 continue;
9447                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9448                 }
9449         }
9450         else
9451         {
9452                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9453                 {
9454                         surfaceindex = surfacelist[surfacelistindex];
9455                         surface = surfaces + surfaceindex;
9456                         // check cull box first because it rejects more than any other check
9457                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9458                                 continue;
9459                         // skip transparent surfaces
9460                         texture = surface->texture;
9461                         if (!texture)
9462                                 continue;
9463                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9464                                 continue;
9465                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9466                                 continue;
9467                         numtriangles = surface->num_triangles;
9468                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9469                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9470                 }
9471         }
9472 }
9473
9474 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9475 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)
9476 {
9477         int renderentityindex;
9478         float worldmins[3];
9479         float worldmaxs[3];
9480         entity_render_t *ent;
9481
9482         worldmins[0] = worldorigin[0] - worldsize;
9483         worldmins[1] = worldorigin[1] - worldsize;
9484         worldmins[2] = worldorigin[2] - worldsize;
9485         worldmaxs[0] = worldorigin[0] + worldsize;
9486         worldmaxs[1] = worldorigin[1] + worldsize;
9487         worldmaxs[2] = worldorigin[2] + worldsize;
9488
9489         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9490
9491         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9492         {
9493                 ent = r_refdef.scene.entities[renderentityindex];
9494                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9495                         continue;
9496
9497                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9498         }
9499 }
9500
9501 typedef struct r_decalsystem_splatqueue_s
9502 {
9503         vec3_t worldorigin;
9504         vec3_t worldnormal;
9505         float color[4];
9506         float tcrange[4];
9507         float worldsize;
9508         unsigned int decalsequence;
9509 }
9510 r_decalsystem_splatqueue_t;
9511
9512 int r_decalsystem_numqueued = 0;
9513 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9514
9515 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)
9516 {
9517         r_decalsystem_splatqueue_t *queue;
9518
9519         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9520                 return;
9521
9522         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9523         VectorCopy(worldorigin, queue->worldorigin);
9524         VectorCopy(worldnormal, queue->worldnormal);
9525         Vector4Set(queue->color, r, g, b, a);
9526         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9527         queue->worldsize = worldsize;
9528         queue->decalsequence = cl.decalsequence++;
9529 }
9530
9531 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9532 {
9533         int i;
9534         r_decalsystem_splatqueue_t *queue;
9535
9536         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9537                 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);
9538         r_decalsystem_numqueued = 0;
9539 }
9540
9541 extern cvar_t cl_decals_max;
9542 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9543 {
9544         int i;
9545         decalsystem_t *decalsystem = &ent->decalsystem;
9546         int numdecals;
9547         unsigned int killsequence;
9548         tridecal_t *decal;
9549         float frametime;
9550         float lifetime;
9551
9552         if (!decalsystem->numdecals)
9553                 return;
9554
9555         if (r_showsurfaces.integer)
9556                 return;
9557
9558         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9559         {
9560                 R_DecalSystem_Reset(decalsystem);
9561                 return;
9562         }
9563
9564         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9565         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9566
9567         if (decalsystem->lastupdatetime)
9568                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9569         else
9570                 frametime = 0;
9571         decalsystem->lastupdatetime = r_refdef.scene.time;
9572         numdecals = decalsystem->numdecals;
9573
9574         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9575         {
9576                 if (decal->color4f[0][3])
9577                 {
9578                         decal->lived += frametime;
9579                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9580                         {
9581                                 memset(decal, 0, sizeof(*decal));
9582                                 if (decalsystem->freedecal > i)
9583                                         decalsystem->freedecal = i;
9584                         }
9585                 }
9586         }
9587         decal = decalsystem->decals;
9588         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9589                 numdecals--;
9590
9591         // collapse the array by shuffling the tail decals into the gaps
9592         for (;;)
9593         {
9594                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9595                         decalsystem->freedecal++;
9596                 if (decalsystem->freedecal == numdecals)
9597                         break;
9598                 decal[decalsystem->freedecal] = decal[--numdecals];
9599         }
9600
9601         decalsystem->numdecals = numdecals;
9602
9603         if (numdecals <= 0)
9604         {
9605                 // if there are no decals left, reset decalsystem
9606                 R_DecalSystem_Reset(decalsystem);
9607         }
9608 }
9609
9610 extern skinframe_t *decalskinframe;
9611 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9612 {
9613         int i;
9614         decalsystem_t *decalsystem = &ent->decalsystem;
9615         int numdecals;
9616         tridecal_t *decal;
9617         float faderate;
9618         float alpha;
9619         float *v3f;
9620         float *c4f;
9621         float *t2f;
9622         const int *e;
9623         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9624         int numtris = 0;
9625
9626         numdecals = decalsystem->numdecals;
9627         if (!numdecals)
9628                 return;
9629
9630         if (r_showsurfaces.integer)
9631                 return;
9632
9633         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9634         {
9635                 R_DecalSystem_Reset(decalsystem);
9636                 return;
9637         }
9638
9639         // if the model is static it doesn't matter what value we give for
9640         // wantnormals and wanttangents, so this logic uses only rules applicable
9641         // to a model, knowing that they are meaningless otherwise
9642         RSurf_ActiveModelEntity(ent, false, false, false);
9643
9644         decalsystem->lastupdatetime = r_refdef.scene.time;
9645
9646         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9647
9648         // update vertex positions for animated models
9649         v3f = decalsystem->vertex3f;
9650         c4f = decalsystem->color4f;
9651         t2f = decalsystem->texcoord2f;
9652         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9653         {
9654                 if (!decal->color4f[0][3])
9655                         continue;
9656
9657                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9658                         continue;
9659
9660                 // skip backfaces
9661                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9662                         continue;
9663
9664                 // update color values for fading decals
9665                 if (decal->lived >= cl_decals_time.value)
9666                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9667                 else
9668                         alpha = 1.0f;
9669
9670                 c4f[ 0] = decal->color4f[0][0] * alpha;
9671                 c4f[ 1] = decal->color4f[0][1] * alpha;
9672                 c4f[ 2] = decal->color4f[0][2] * alpha;
9673                 c4f[ 3] = 1;
9674                 c4f[ 4] = decal->color4f[1][0] * alpha;
9675                 c4f[ 5] = decal->color4f[1][1] * alpha;
9676                 c4f[ 6] = decal->color4f[1][2] * alpha;
9677                 c4f[ 7] = 1;
9678                 c4f[ 8] = decal->color4f[2][0] * alpha;
9679                 c4f[ 9] = decal->color4f[2][1] * alpha;
9680                 c4f[10] = decal->color4f[2][2] * alpha;
9681                 c4f[11] = 1;
9682
9683                 t2f[0] = decal->texcoord2f[0][0];
9684                 t2f[1] = decal->texcoord2f[0][1];
9685                 t2f[2] = decal->texcoord2f[1][0];
9686                 t2f[3] = decal->texcoord2f[1][1];
9687                 t2f[4] = decal->texcoord2f[2][0];
9688                 t2f[5] = decal->texcoord2f[2][1];
9689
9690                 // update vertex positions for animated models
9691                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9692                 {
9693                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9694                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9695                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9696                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9697                 }
9698                 else
9699                 {
9700                         VectorCopy(decal->vertex3f[0], v3f);
9701                         VectorCopy(decal->vertex3f[1], v3f + 3);
9702                         VectorCopy(decal->vertex3f[2], v3f + 6);
9703                 }
9704
9705                 if (r_refdef.fogenabled)
9706                 {
9707                         alpha = RSurf_FogVertex(v3f);
9708                         VectorScale(c4f, alpha, c4f);
9709                         alpha = RSurf_FogVertex(v3f + 3);
9710                         VectorScale(c4f + 4, alpha, c4f + 4);
9711                         alpha = RSurf_FogVertex(v3f + 6);
9712                         VectorScale(c4f + 8, alpha, c4f + 8);
9713                 }
9714
9715                 v3f += 9;
9716                 c4f += 12;
9717                 t2f += 6;
9718                 numtris++;
9719         }
9720
9721         if (numtris > 0)
9722         {
9723                 r_refdef.stats[r_stat_drawndecals] += numtris;
9724
9725                 // now render the decals all at once
9726                 // (this assumes they all use one particle font texture!)
9727                 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);
9728 //              R_Mesh_ResetTextureState();
9729                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9730                 GL_DepthMask(false);
9731                 GL_DepthRange(0, 1);
9732                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9733                 GL_DepthTest(true);
9734                 GL_CullFace(GL_NONE);
9735                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9736                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9737                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9738         }
9739 }
9740
9741 static void R_DrawModelDecals(void)
9742 {
9743         int i, numdecals;
9744
9745         // fade faster when there are too many decals
9746         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9747         for (i = 0;i < r_refdef.scene.numentities;i++)
9748                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9749
9750         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9751         for (i = 0;i < r_refdef.scene.numentities;i++)
9752                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9753                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9754
9755         R_DecalSystem_ApplySplatEntitiesQueue();
9756
9757         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9758         for (i = 0;i < r_refdef.scene.numentities;i++)
9759                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9760
9761         r_refdef.stats[r_stat_totaldecals] += numdecals;
9762
9763         if (r_showsurfaces.integer || !r_drawdecals.integer)
9764                 return;
9765
9766         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9767
9768         for (i = 0;i < r_refdef.scene.numentities;i++)
9769         {
9770                 if (!r_refdef.viewcache.entityvisible[i])
9771                         continue;
9772                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9773                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9774         }
9775 }
9776
9777 static void R_DrawDebugModel(void)
9778 {
9779         entity_render_t *ent = rsurface.entity;
9780         int i, j, flagsmask;
9781         const msurface_t *surface;
9782         model_t *model = ent->model;
9783
9784         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9785                 return;
9786
9787         if (r_showoverdraw.value > 0)
9788         {
9789                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9790                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9791                 R_SetupShader_Generic_NoTexture(false, false);
9792                 GL_DepthTest(false);
9793                 GL_DepthMask(false);
9794                 GL_DepthRange(0, 1);
9795                 GL_BlendFunc(GL_ONE, GL_ONE);
9796                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9797                 {
9798                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9799                                 continue;
9800                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9801                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9802                         {
9803                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9804                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9805                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9806                                         GL_Color(c, 0, 0, 1.0f);
9807                                 else if (ent == r_refdef.scene.worldentity)
9808                                         GL_Color(c, c, c, 1.0f);
9809                                 else
9810                                         GL_Color(0, c, 0, 1.0f);
9811                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9812                                 RSurf_DrawBatch();
9813                         }
9814                 }
9815                 rsurface.texture = NULL;
9816         }
9817
9818         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9819
9820 //      R_Mesh_ResetTextureState();
9821         R_SetupShader_Generic_NoTexture(false, false);
9822         GL_DepthRange(0, 1);
9823         GL_DepthTest(!r_showdisabledepthtest.integer);
9824         GL_DepthMask(false);
9825         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9826
9827         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9828         {
9829                 int triangleindex;
9830                 int bihleafindex;
9831                 qbool cullbox = false;
9832                 const q3mbrush_t *brush;
9833                 const bih_t *bih = &model->collision_bih;
9834                 const bih_leaf_t *bihleaf;
9835                 float vertex3f[3][3];
9836                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9837                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9838                 {
9839                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9840                                 continue;
9841                         switch (bihleaf->type)
9842                         {
9843                         case BIH_BRUSH:
9844                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9845                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9846                                 {
9847                                         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);
9848                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9849                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9850                                 }
9851                                 break;
9852                         case BIH_COLLISIONTRIANGLE:
9853                                 triangleindex = bihleaf->itemindex;
9854                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9855                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9856                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9857                                 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);
9858                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9859                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9860                                 break;
9861                         case BIH_RENDERTRIANGLE:
9862                                 triangleindex = bihleaf->itemindex;
9863                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9864                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9865                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9866                                 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);
9867                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9868                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9869                                 break;
9870                         }
9871                 }
9872         }
9873
9874         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9875
9876 #ifndef USE_GLES2
9877         if (r_showtris.value > 0 && qglPolygonMode)
9878         {
9879                 if (r_showdisabledepthtest.integer)
9880                 {
9881                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9882                         GL_DepthMask(false);
9883                 }
9884                 else
9885                 {
9886                         GL_BlendFunc(GL_ONE, GL_ZERO);
9887                         GL_DepthMask(true);
9888                 }
9889                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9890                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9891                 {
9892                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9893                                 continue;
9894                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9895                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9896                         {
9897                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9898                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9899                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9900                                 else if (ent == r_refdef.scene.worldentity)
9901                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9902                                 else
9903                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9904                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9905                                 RSurf_DrawBatch();
9906                         }
9907                 }
9908                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9909                 rsurface.texture = NULL;
9910         }
9911
9912 # if 0
9913         // FIXME!  implement r_shownormals with just triangles
9914         if (r_shownormals.value != 0 && qglBegin)
9915         {
9916                 int l, k;
9917                 vec3_t v;
9918                 if (r_showdisabledepthtest.integer)
9919                 {
9920                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9921                         GL_DepthMask(false);
9922                 }
9923                 else
9924                 {
9925                         GL_BlendFunc(GL_ONE, GL_ZERO);
9926                         GL_DepthMask(true);
9927                 }
9928                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9929                 {
9930                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9931                                 continue;
9932                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9933                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9934                         {
9935                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9936                                 qglBegin(GL_LINES);
9937                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9938                                 {
9939                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9940                                         {
9941                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9942                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9943                                                 qglVertex3f(v[0], v[1], v[2]);
9944                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9945                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9946                                                 qglVertex3f(v[0], v[1], v[2]);
9947                                         }
9948                                 }
9949                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9950                                 {
9951                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9952                                         {
9953                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9954                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9955                                                 qglVertex3f(v[0], v[1], v[2]);
9956                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9957                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9958                                                 qglVertex3f(v[0], v[1], v[2]);
9959                                         }
9960                                 }
9961                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9962                                 {
9963                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9964                                         {
9965                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9966                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9967                                                 qglVertex3f(v[0], v[1], v[2]);
9968                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9969                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9970                                                 qglVertex3f(v[0], v[1], v[2]);
9971                                         }
9972                                 }
9973                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9974                                 {
9975                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9976                                         {
9977                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9978                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9979                                                 qglVertex3f(v[0], v[1], v[2]);
9980                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9981                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9982                                                 qglVertex3f(v[0], v[1], v[2]);
9983                                         }
9984                                 }
9985                                 qglEnd();
9986                                 CHECKGLERROR
9987                         }
9988                 }
9989                 rsurface.texture = NULL;
9990         }
9991 # endif
9992 #endif
9993 }
9994
9995 int r_maxsurfacelist = 0;
9996 const msurface_t **r_surfacelist = NULL;
9997 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
9998 {
9999         int i, j, flagsmask;
10000         model_t *model = ent->model;
10001         msurface_t *surfaces;
10002         unsigned char *update;
10003         int numsurfacelist = 0;
10004         if (model == NULL)
10005                 return;
10006
10007         if (r_maxsurfacelist < model->num_surfaces)
10008         {
10009                 r_maxsurfacelist = model->num_surfaces;
10010                 if (r_surfacelist)
10011                         Mem_Free((msurface_t **)r_surfacelist);
10012                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10013         }
10014
10015         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10016                 RSurf_ActiveModelEntity(ent, false, false, false);
10017         else if (prepass)
10018                 RSurf_ActiveModelEntity(ent, true, true, true);
10019         else if (depthonly)
10020                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10021         else
10022                 RSurf_ActiveModelEntity(ent, true, true, false);
10023
10024         surfaces = model->data_surfaces;
10025         update = model->brushq1.lightmapupdateflags;
10026
10027         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10028
10029         if (debug)
10030         {
10031                 R_DrawDebugModel();
10032                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10033                 return;
10034         }
10035
10036         // check if this is an empty model
10037         if (model->nummodelsurfaces == 0)
10038                 return;
10039
10040         rsurface.lightmaptexture = NULL;
10041         rsurface.deluxemaptexture = NULL;
10042         rsurface.uselightmaptexture = false;
10043         rsurface.texture = NULL;
10044         rsurface.rtlight = NULL;
10045         numsurfacelist = 0;
10046
10047         // add visible surfaces to draw list
10048         if (ent == r_refdef.scene.worldentity)
10049         {
10050                 // for the world entity, check surfacevisible
10051                 for (i = 0;i < model->nummodelsurfaces;i++)
10052                 {
10053                         j = model->sortedmodelsurfaces[i];
10054                         if (r_refdef.viewcache.world_surfacevisible[j])
10055                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10056                 }
10057
10058                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10059                 if (!numsurfacelist)
10060                 {
10061                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10062                         return;
10063                 }
10064         }
10065         else if (ui)
10066         {
10067                 // for ui we have to preserve the order of surfaces (not using sortedmodelsurfaces)
10068                 for (i = 0; i < model->nummodelsurfaces; i++)
10069                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10070         }
10071         else
10072         {
10073                 // add all surfaces
10074                 for (i = 0; i < model->nummodelsurfaces; i++)
10075                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10076         }
10077
10078         /*
10079          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10080          * using style chains because most styles do not change on most frames, and most
10081          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10082          * break this rule and animate most surfaces.
10083          */
10084         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10085         {
10086                 model_brush_lightstyleinfo_t *style;
10087
10088                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10089                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10090                 {
10091                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10092                         {
10093                                 int* list = style->surfacelist;
10094                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10095                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10096                                 for (j = 0; j < style->numsurfaces; j++)
10097                                         update[list[j]] = true;
10098                         }
10099                 }
10100                 // Now check if update flags are set on any surfaces that are visible
10101                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10102                 {
10103                         /* 
10104                          * We can do less frequent texture uploads (approximately 10hz for animated
10105                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10106                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10107                          * use model->num_surfaces, not nummodelsurfaces.
10108                          */
10109                         for (i = 0; i < model->num_surfaces;i++)
10110                                 if (update[i])
10111                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10112                 }
10113                 else
10114                 {
10115                         for (i = 0; i < numsurfacelist; i++)
10116                                 if (update[r_surfacelist[i] - surfaces])
10117                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10118                 }
10119         }
10120
10121         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10122
10123         // add to stats if desired
10124         if (r_speeds.integer && !skysurfaces && !depthonly)
10125         {
10126                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10127                 for (j = 0;j < numsurfacelist;j++)
10128                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10129         }
10130
10131         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10132 }
10133
10134 void R_DebugLine(vec3_t start, vec3_t end)
10135 {
10136         model_t *mod = CL_Mesh_UI();
10137         msurface_t *surf;
10138         int e0, e1, e2, e3;
10139         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10140         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10141         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10142         vec4_t w[2], s[2];
10143
10144         // transform to screen coords first
10145         Vector4Set(w[0], start[0], start[1], start[2], 1);
10146         Vector4Set(w[1], end[0], end[1], end[2], 1);
10147         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10148         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10149         x1 = s[0][0] * vid_conwidth.value / vid.width;
10150         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10151         x2 = s[1][0] * vid_conwidth.value / vid.width;
10152         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10153         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10154
10155         // add the line to the UI mesh for drawing later
10156
10157         // width is measured in real pixels
10158         if (fabs(x2 - x1) > fabs(y2 - y1))
10159         {
10160                 offsetx = 0;
10161                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10162         }
10163         else
10164         {
10165                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10166                 offsety = 0;
10167         }
10168         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);
10169         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10170         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10171         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10172         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10173         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10174         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10175
10176 }
10177
10178
10179 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10180 {
10181         static texture_t texture;
10182
10183         // fake enough texture and surface state to render this geometry
10184
10185         texture.update_lastrenderframe = -1; // regenerate this texture
10186         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10187         texture.basealpha = 1.0f;
10188         texture.currentskinframe = skinframe;
10189         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10190         texture.offsetmapping = OFFSETMAPPING_OFF;
10191         texture.offsetscale = 1;
10192         texture.specularscalemod = 1;
10193         texture.specularpowermod = 1;
10194         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10195
10196         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10197 }
10198
10199 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10200 {
10201         static msurface_t surface;
10202         const msurface_t *surfacelist = &surface;
10203
10204         // fake enough texture and surface state to render this geometry
10205         surface.texture = texture;
10206         surface.num_triangles = numtriangles;
10207         surface.num_firsttriangle = firsttriangle;
10208         surface.num_vertices = numvertices;
10209         surface.num_firstvertex = firstvertex;
10210
10211         // now render it
10212         rsurface.texture = R_GetCurrentTexture(surface.texture);
10213         rsurface.lightmaptexture = NULL;
10214         rsurface.deluxemaptexture = NULL;
10215         rsurface.uselightmaptexture = false;
10216         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10217 }