]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qbool r_loadnormalmap;
48 static qbool r_loadgloss;
49 qbool r_loadfog;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 3 shows an approximation to vertex or object color (for a very approximate view of the game)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CF_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
160 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode; the default setting of 0 uses a framebuffer render when required, and renders directly to the screen otherwise"};
161 cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
162 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
163 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
164 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
165 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
166 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
167 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
168 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
169
170 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
171 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
172 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
173 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
174 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
175 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
176 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
177 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
178 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
179 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
180 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
181 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
182 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
183 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
184 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
185 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
189 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
190 cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"};
191
192 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
193 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
194 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
195 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
196 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
197 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
198 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
199 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
200 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
201
202 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
203 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
204 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
205 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
206 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
207
208 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
209 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
210
211 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
212 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
213 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
214 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
215 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
216 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
217
218 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
219 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
220 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
221 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
222 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
223 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
224 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
225 cvar_t r_hdr_irisadaptation_fade_up = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
226 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
227 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
228
229 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
230
231 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
232
233 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
234
235 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
236
237 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
238 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
239 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
240 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
241
242 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
243 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
244
245 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
246
247 // FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting.
248 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
249 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
250 {
251         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
252         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
253         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
254         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
255 };
256
257 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
258 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
259 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
260
261 extern cvar_t v_glslgamma_2d;
262
263 extern qbool v_flipped_state;
264
265 r_framebufferstate_t r_fb;
266
267 /// shadow volume bsp struct with automatically growing nodes buffer
268 svbsp_t r_svbsp;
269
270 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
271
272 rtexture_t *r_texture_blanknormalmap;
273 rtexture_t *r_texture_white;
274 rtexture_t *r_texture_grey128;
275 rtexture_t *r_texture_black;
276 rtexture_t *r_texture_notexture;
277 rtexture_t *r_texture_whitecube;
278 rtexture_t *r_texture_normalizationcube;
279 rtexture_t *r_texture_fogattenuation;
280 rtexture_t *r_texture_fogheighttexture;
281 rtexture_t *r_texture_gammaramps;
282 unsigned int r_texture_gammaramps_serial;
283 //rtexture_t *r_texture_fogintensity;
284 rtexture_t *r_texture_reflectcube;
285
286 // TODO: hash lookups?
287 typedef struct cubemapinfo_s
288 {
289         char basename[64];
290         rtexture_t *texture;
291 }
292 cubemapinfo_t;
293
294 int r_texture_numcubemaps;
295 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
296
297 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
298 unsigned int r_numqueries;
299 unsigned int r_maxqueries;
300
301 typedef struct r_qwskincache_s
302 {
303         char name[MAX_QPATH];
304         skinframe_t *skinframe;
305 }
306 r_qwskincache_t;
307
308 static r_qwskincache_t *r_qwskincache;
309 static int r_qwskincache_size;
310
311 /// vertex coordinates for a quad that covers the screen exactly
312 extern const float r_screenvertex3f[12];
313 const float r_screenvertex3f[12] =
314 {
315         0, 0, 0,
316         1, 0, 0,
317         1, 1, 0,
318         0, 1, 0
319 };
320
321 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
322 {
323         int i;
324         for (i = 0;i < verts;i++)
325         {
326                 out[0] = in[0] * r;
327                 out[1] = in[1] * g;
328                 out[2] = in[2] * b;
329                 out[3] = in[3];
330                 in += 4;
331                 out += 4;
332         }
333 }
334
335 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
336 {
337         int i;
338         for (i = 0;i < verts;i++)
339         {
340                 out[0] = r;
341                 out[1] = g;
342                 out[2] = b;
343                 out[3] = a;
344                 out += 4;
345         }
346 }
347
348 // FIXME: move this to client?
349 void FOG_clear(void)
350 {
351         if (gamemode == GAME_NEHAHRA)
352         {
353                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
354                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
355                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
356                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
357                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
358         }
359         r_refdef.fog_density = 0;
360         r_refdef.fog_red = 0;
361         r_refdef.fog_green = 0;
362         r_refdef.fog_blue = 0;
363         r_refdef.fog_alpha = 1;
364         r_refdef.fog_start = 0;
365         r_refdef.fog_end = 16384;
366         r_refdef.fog_height = 1<<30;
367         r_refdef.fog_fadedepth = 128;
368         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
369 }
370
371 static void R_BuildBlankTextures(void)
372 {
373         unsigned char data[4];
374         data[2] = 128; // normal X
375         data[1] = 128; // normal Y
376         data[0] = 255; // normal Z
377         data[3] = 255; // height
378         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
379         data[0] = 255;
380         data[1] = 255;
381         data[2] = 255;
382         data[3] = 255;
383         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
384         data[0] = 128;
385         data[1] = 128;
386         data[2] = 128;
387         data[3] = 255;
388         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
389         data[0] = 0;
390         data[1] = 0;
391         data[2] = 0;
392         data[3] = 255;
393         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
394 }
395
396 static void R_BuildNoTexture(void)
397 {
398         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
399 }
400
401 static void R_BuildWhiteCube(void)
402 {
403         unsigned char data[6*1*1*4];
404         memset(data, 255, sizeof(data));
405         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
406 }
407
408 static void R_BuildNormalizationCube(void)
409 {
410         int x, y, side;
411         vec3_t v;
412         vec_t s, t, intensity;
413 #define NORMSIZE 64
414         unsigned char *data;
415         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
416         for (side = 0;side < 6;side++)
417         {
418                 for (y = 0;y < NORMSIZE;y++)
419                 {
420                         for (x = 0;x < NORMSIZE;x++)
421                         {
422                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
423                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
424                                 switch(side)
425                                 {
426                                 default:
427                                 case 0:
428                                         v[0] = 1;
429                                         v[1] = -t;
430                                         v[2] = -s;
431                                         break;
432                                 case 1:
433                                         v[0] = -1;
434                                         v[1] = -t;
435                                         v[2] = s;
436                                         break;
437                                 case 2:
438                                         v[0] = s;
439                                         v[1] = 1;
440                                         v[2] = t;
441                                         break;
442                                 case 3:
443                                         v[0] = s;
444                                         v[1] = -1;
445                                         v[2] = -t;
446                                         break;
447                                 case 4:
448                                         v[0] = s;
449                                         v[1] = -t;
450                                         v[2] = 1;
451                                         break;
452                                 case 5:
453                                         v[0] = -s;
454                                         v[1] = -t;
455                                         v[2] = -1;
456                                         break;
457                                 }
458                                 intensity = 127.0f / sqrt(DotProduct(v, v));
459                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
460                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
461                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
462                                 data[((side*64+y)*64+x)*4+3] = 255;
463                         }
464                 }
465         }
466         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
467         Mem_Free(data);
468 }
469
470 static void R_BuildFogTexture(void)
471 {
472         int x, b;
473 #define FOGWIDTH 256
474         unsigned char data1[FOGWIDTH][4];
475         //unsigned char data2[FOGWIDTH][4];
476         double d, r, alpha;
477
478         r_refdef.fogmasktable_start = r_refdef.fog_start;
479         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
480         r_refdef.fogmasktable_range = r_refdef.fogrange;
481         r_refdef.fogmasktable_density = r_refdef.fog_density;
482
483         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
484         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
485         {
486                 d = (x * r - r_refdef.fogmasktable_start);
487                 if(developer_extra.integer)
488                         Con_DPrintf("%f ", d);
489                 d = max(0, d);
490                 if (r_fog_exp2.integer)
491                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
492                 else
493                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
494                 if(developer_extra.integer)
495                         Con_DPrintf(" : %f ", alpha);
496                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
497                 if(developer_extra.integer)
498                         Con_DPrintf(" = %f\n", alpha);
499                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
500         }
501
502         for (x = 0;x < FOGWIDTH;x++)
503         {
504                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
505                 data1[x][0] = b;
506                 data1[x][1] = b;
507                 data1[x][2] = b;
508                 data1[x][3] = 255;
509                 //data2[x][0] = 255 - b;
510                 //data2[x][1] = 255 - b;
511                 //data2[x][2] = 255 - b;
512                 //data2[x][3] = 255;
513         }
514         if (r_texture_fogattenuation)
515         {
516                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
517                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
518         }
519         else
520         {
521                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
522                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
523         }
524 }
525
526 static void R_BuildFogHeightTexture(void)
527 {
528         unsigned char *inpixels;
529         int size;
530         int x;
531         int y;
532         int j;
533         float c[4];
534         float f;
535         inpixels = NULL;
536         dp_strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
537         if (r_refdef.fogheighttexturename[0])
538                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
539         if (!inpixels)
540         {
541                 r_refdef.fog_height_tablesize = 0;
542                 if (r_texture_fogheighttexture)
543                         R_FreeTexture(r_texture_fogheighttexture);
544                 r_texture_fogheighttexture = NULL;
545                 if (r_refdef.fog_height_table2d)
546                         Mem_Free(r_refdef.fog_height_table2d);
547                 r_refdef.fog_height_table2d = NULL;
548                 if (r_refdef.fog_height_table1d)
549                         Mem_Free(r_refdef.fog_height_table1d);
550                 r_refdef.fog_height_table1d = NULL;
551                 return;
552         }
553         size = image_width;
554         r_refdef.fog_height_tablesize = size;
555         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
556         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
557         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
558         Mem_Free(inpixels);
559         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
560         // average fog color table accounting for every fog layer between a point
561         // and the camera.  (Note: attenuation is handled separately!)
562         for (y = 0;y < size;y++)
563         {
564                 for (x = 0;x < size;x++)
565                 {
566                         Vector4Clear(c);
567                         f = 0;
568                         if (x < y)
569                         {
570                                 for (j = x;j <= y;j++)
571                                 {
572                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
573                                         f++;
574                                 }
575                         }
576                         else
577                         {
578                                 for (j = x;j >= y;j--)
579                                 {
580                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
581                                         f++;
582                                 }
583                         }
584                         f = 1.0f / f;
585                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
586                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
587                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
588                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
589                 }
590         }
591         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
592 }
593
594 //=======================================================================================================================================================
595
596 static const char *builtinshaderstrings[] =
597 {
598 #include "shader_glsl.h"
599 0
600 };
601
602 //=======================================================================================================================================================
603
604 typedef struct shaderpermutationinfo_s
605 {
606         const char *pretext;
607         const char *name;
608 }
609 shaderpermutationinfo_t;
610
611 typedef struct shadermodeinfo_s
612 {
613         const char *sourcebasename;
614         const char *extension;
615         const char **builtinshaderstrings;
616         const char *pretext;
617         const char *name;
618         char *filename;
619         char *builtinstring;
620         int builtincrc;
621 }
622 shadermodeinfo_t;
623
624 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
625 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
626 {
627         {"#define USEDIFFUSE\n", " diffuse"},
628         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
629         {"#define USEVIEWTINT\n", " viewtint"},
630         {"#define USECOLORMAPPING\n", " colormapping"},
631         {"#define USESATURATION\n", " saturation"},
632         {"#define USEFOGINSIDE\n", " foginside"},
633         {"#define USEFOGOUTSIDE\n", " fogoutside"},
634         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
635         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
636         {"#define USEGAMMARAMPS\n", " gammaramps"},
637         {"#define USECUBEFILTER\n", " cubefilter"},
638         {"#define USEGLOW\n", " glow"},
639         {"#define USEBLOOM\n", " bloom"},
640         {"#define USESPECULAR\n", " specular"},
641         {"#define USEPOSTPROCESSING\n", " postprocessing"},
642         {"#define USEREFLECTION\n", " reflection"},
643         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
644         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
645         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
646         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
647         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
648         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
649         {"#define USEALPHAKILL\n", " alphakill"},
650         {"#define USEREFLECTCUBE\n", " reflectcube"},
651         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
652         {"#define USEBOUNCEGRID\n", " bouncegrid"},
653         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
654         {"#define USETRIPPY\n", " trippy"},
655         {"#define USEDEPTHRGB\n", " depthrgb"},
656         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
657         {"#define USESKELETAL\n", " skeletal"},
658         {"#define USEOCCLUDE\n", " occlude"}
659 };
660
661 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
662 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
663 {
664         // SHADERLANGUAGE_GLSL
665         {
666                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
667                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
668                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
669                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
683         },
684 };
685
686 struct r_glsl_permutation_s;
687 typedef struct r_glsl_permutation_s
688 {
689         /// hash lookup data
690         struct r_glsl_permutation_s *hashnext;
691         unsigned int mode;
692         uint64_t permutation;
693
694         /// indicates if we have tried compiling this permutation already
695         qbool compiled;
696         /// 0 if compilation failed
697         int program;
698         // texture units assigned to each detected uniform
699         int tex_Texture_First;
700         int tex_Texture_Second;
701         int tex_Texture_GammaRamps;
702         int tex_Texture_Normal;
703         int tex_Texture_Color;
704         int tex_Texture_Gloss;
705         int tex_Texture_Glow;
706         int tex_Texture_SecondaryNormal;
707         int tex_Texture_SecondaryColor;
708         int tex_Texture_SecondaryGloss;
709         int tex_Texture_SecondaryGlow;
710         int tex_Texture_Pants;
711         int tex_Texture_Shirt;
712         int tex_Texture_FogHeightTexture;
713         int tex_Texture_FogMask;
714         int tex_Texture_LightGrid;
715         int tex_Texture_Lightmap;
716         int tex_Texture_Deluxemap;
717         int tex_Texture_Attenuation;
718         int tex_Texture_Cube;
719         int tex_Texture_Refraction;
720         int tex_Texture_Reflection;
721         int tex_Texture_ShadowMap2D;
722         int tex_Texture_CubeProjection;
723         int tex_Texture_ScreenNormalMap;
724         int tex_Texture_ScreenDiffuse;
725         int tex_Texture_ScreenSpecular;
726         int tex_Texture_ReflectMask;
727         int tex_Texture_ReflectCube;
728         int tex_Texture_BounceGrid;
729         /// locations of detected uniforms in program object, or -1 if not found
730         int loc_Texture_First;
731         int loc_Texture_Second;
732         int loc_Texture_GammaRamps;
733         int loc_Texture_Normal;
734         int loc_Texture_Color;
735         int loc_Texture_Gloss;
736         int loc_Texture_Glow;
737         int loc_Texture_SecondaryNormal;
738         int loc_Texture_SecondaryColor;
739         int loc_Texture_SecondaryGloss;
740         int loc_Texture_SecondaryGlow;
741         int loc_Texture_Pants;
742         int loc_Texture_Shirt;
743         int loc_Texture_FogHeightTexture;
744         int loc_Texture_FogMask;
745         int loc_Texture_LightGrid;
746         int loc_Texture_Lightmap;
747         int loc_Texture_Deluxemap;
748         int loc_Texture_Attenuation;
749         int loc_Texture_Cube;
750         int loc_Texture_Refraction;
751         int loc_Texture_Reflection;
752         int loc_Texture_ShadowMap2D;
753         int loc_Texture_CubeProjection;
754         int loc_Texture_ScreenNormalMap;
755         int loc_Texture_ScreenDiffuse;
756         int loc_Texture_ScreenSpecular;
757         int loc_Texture_ReflectMask;
758         int loc_Texture_ReflectCube;
759         int loc_Texture_BounceGrid;
760         int loc_Alpha;
761         int loc_BloomBlur_Parameters;
762         int loc_ClientTime;
763         int loc_Color_Ambient;
764         int loc_Color_Diffuse;
765         int loc_Color_Specular;
766         int loc_Color_Glow;
767         int loc_Color_Pants;
768         int loc_Color_Shirt;
769         int loc_DeferredColor_Ambient;
770         int loc_DeferredColor_Diffuse;
771         int loc_DeferredColor_Specular;
772         int loc_DeferredMod_Diffuse;
773         int loc_DeferredMod_Specular;
774         int loc_DistortScaleRefractReflect;
775         int loc_EyePosition;
776         int loc_FogColor;
777         int loc_FogHeightFade;
778         int loc_FogPlane;
779         int loc_FogPlaneViewDist;
780         int loc_FogRangeRecip;
781         int loc_LightColor;
782         int loc_LightDir;
783         int loc_LightGridMatrix;
784         int loc_LightGridNormalMatrix;
785         int loc_LightPosition;
786         int loc_OffsetMapping_ScaleSteps;
787         int loc_OffsetMapping_LodDistance;
788         int loc_OffsetMapping_Bias;
789         int loc_PixelSize;
790         int loc_ReflectColor;
791         int loc_ReflectFactor;
792         int loc_ReflectOffset;
793         int loc_RefractColor;
794         int loc_Saturation;
795         int loc_ScreenCenterRefractReflect;
796         int loc_ScreenScaleRefractReflect;
797         int loc_ScreenToDepth;
798         int loc_ShadowMap_Parameters;
799         int loc_ShadowMap_TextureScale;
800         int loc_SpecularPower;
801         int loc_Skeletal_Transform12;
802         int loc_UserVec1;
803         int loc_UserVec2;
804         int loc_UserVec3;
805         int loc_UserVec4;
806         int loc_ColorFringe;
807         int loc_ViewTintColor;
808         int loc_ViewToLight;
809         int loc_ModelToLight;
810         int loc_TexMatrix;
811         int loc_BackgroundTexMatrix;
812         int loc_ModelViewProjectionMatrix;
813         int loc_ModelViewMatrix;
814         int loc_PixelToScreenTexCoord;
815         int loc_ModelToReflectCube;
816         int loc_ShadowMapMatrix;
817         int loc_BloomColorSubtract;
818         int loc_NormalmapScrollBlend;
819         int loc_BounceGridMatrix;
820         int loc_BounceGridIntensity;
821         /// uniform block bindings
822         int ubibind_Skeletal_Transform12_UniformBlock;
823         /// uniform block indices
824         int ubiloc_Skeletal_Transform12_UniformBlock;
825 }
826 r_glsl_permutation_t;
827
828 #define SHADERPERMUTATION_HASHSIZE 256
829
830
831 // non-degradable "lightweight" shader parameters to keep the permutations simpler
832 // these can NOT degrade! only use for simple stuff
833 enum
834 {
835         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
836         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
837         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
838         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
839         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
840         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
841         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
842         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
843         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
844         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
845         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
846         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
847         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
848         SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
849         SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
850 };
851 #define SHADERSTATICPARMS_COUNT 15
852
853 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
854 static int shaderstaticparms_count = 0;
855
856 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
857 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
858
859 extern qbool r_shadow_shadowmapsampler;
860 extern int r_shadow_shadowmappcf;
861 qbool R_CompileShader_CheckStaticParms(void)
862 {
863         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
864         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
865         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
866
867         // detect all
868         if (r_glsl_saturation_redcompensate.integer)
869                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
870         if (r_glsl_vertextextureblend_usebothalphas.integer)
871                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
872         if (r_shadow_glossexact.integer)
873                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
874         if (r_glsl_postprocess.integer)
875         {
876                 if (r_glsl_postprocess_uservec1_enable.integer)
877                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
878                 if (r_glsl_postprocess_uservec2_enable.integer)
879                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
880                 if (r_glsl_postprocess_uservec3_enable.integer)
881                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
882                 if (r_glsl_postprocess_uservec4_enable.integer)
883                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
884         }
885         if (r_fxaa.integer)
886                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
887         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
888                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
889
890         if (r_shadow_shadowmapsampler)
891                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
892         if (r_shadow_shadowmappcf > 1)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
894         else if (r_shadow_shadowmappcf)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
896         if (r_celshading.integer)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
898         if (r_celoutlines.integer)
899                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
900         if (r_colorfringe.value)
901                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
902
903         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
904 }
905
906 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
907         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
908                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
909         else \
910                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
911 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
912 {
913         shaderstaticparms_count = 0;
914
915         // emit all
916         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
917         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
918         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
919         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
931 }
932
933 /// information about each possible shader permutation
934 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
935 /// currently selected permutation
936 r_glsl_permutation_t *r_glsl_permutation;
937 /// storage for permutations linked in the hash table
938 memexpandablearray_t r_glsl_permutationarray;
939
940 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
941 {
942         //unsigned int hashdepth = 0;
943         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
944         r_glsl_permutation_t *p;
945         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
946         {
947                 if (p->mode == mode && p->permutation == permutation)
948                 {
949                         //if (hashdepth > 10)
950                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
951                         return p;
952                 }
953                 //hashdepth++;
954         }
955         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
956         p->mode = mode;
957         p->permutation = permutation;
958         p->hashnext = r_glsl_permutationhash[mode][hashindex];
959         r_glsl_permutationhash[mode][hashindex] = p;
960         //if (hashdepth > 10)
961         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
962         return p;
963 }
964
965 static char *R_ShaderStrCat(const char **strings)
966 {
967         char *string, *s;
968         const char **p = strings;
969         const char *t;
970         size_t len = 0;
971         for (p = strings;(t = *p);p++)
972                 len += strlen(t);
973         len++;
974         s = string = (char *)Mem_Alloc(r_main_mempool, len);
975         len = 0;
976         for (p = strings;(t = *p);p++)
977         {
978                 len = strlen(t);
979                 memcpy(s, t, len);
980                 s += len;
981         }
982         *s = 0;
983         return string;
984 }
985
986 static char *R_ShaderStrCat(const char **strings);
987 static void R_InitShaderModeInfo(void)
988 {
989         int i, language;
990         shadermodeinfo_t *modeinfo;
991         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
992         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
993         {
994                 for (i = 0; i < SHADERMODE_COUNT; i++)
995                 {
996                         char filename[MAX_QPATH];
997                         modeinfo = &shadermodeinfo[language][i];
998                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
999                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1000                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1001                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1002                 }
1003         }
1004 }
1005
1006 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1007 {
1008         char *shaderstring;
1009         // if the mode has no filename we have to return the builtin string
1010         if (builtinonly || !modeinfo->filename)
1011                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1012         // note that FS_LoadFile appends a 0 byte to make it a valid string
1013         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1014         if (shaderstring)
1015         {
1016                 if (printfromdisknotice)
1017                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1018                 return shaderstring;
1019         }
1020         // fall back to builtinstring
1021         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1022 }
1023
1024 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1025 {
1026         unsigned i;
1027         int ubibind;
1028         int sampler;
1029         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1030         char *sourcestring;
1031         char permutationname[256];
1032         int vertstrings_count = 0;
1033         int geomstrings_count = 0;
1034         int fragstrings_count = 0;
1035         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1036         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1037         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1038
1039         if (p->compiled)
1040                 return;
1041         p->compiled = true;
1042         p->program = 0;
1043
1044         permutationname[0] = 0;
1045         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1046
1047         dp_strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1048
1049         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1050         if(vid.support.glshaderversion >= 140)
1051         {
1052                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1053                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1054                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1055                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1056                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1057                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1058         }
1059         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1060         else if(vid.support.glshaderversion >= 130)
1061         {
1062                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1063                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1064                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1065                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1066                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1067                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1068         }
1069         // if we can do #version 120, we should (this adds the invariant keyword)
1070         else if(vid.support.glshaderversion >= 120)
1071         {
1072                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1073                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1074                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1075                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1076                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1077                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1078         }
1079         // GLES also adds several things from GLSL120
1080         switch(vid.renderpath)
1081         {
1082         case RENDERPATH_GLES2:
1083                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1084                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1085                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1086                 break;
1087         default:
1088                 break;
1089         }
1090
1091         // the first pretext is which type of shader to compile as
1092         // (later these will all be bound together as a program object)
1093         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1094         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1095         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1096
1097         // the second pretext is the mode (for example a light source)
1098         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1099         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1100         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1101         dp_strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1102
1103         // now add all the permutation pretexts
1104         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1105         {
1106                 if (permutation & (1ll<<i))
1107                 {
1108                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1109                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1110                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1111                         dp_strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1112                 }
1113                 else
1114                 {
1115                         // keep line numbers correct
1116                         vertstrings_list[vertstrings_count++] = "\n";
1117                         geomstrings_list[geomstrings_count++] = "\n";
1118                         fragstrings_list[fragstrings_count++] = "\n";
1119                 }
1120         }
1121
1122         // add static parms
1123         R_CompileShader_AddStaticParms(mode, permutation);
1124         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1125         vertstrings_count += shaderstaticparms_count;
1126         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1127         geomstrings_count += shaderstaticparms_count;
1128         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1129         fragstrings_count += shaderstaticparms_count;
1130
1131         // now append the shader text itself
1132         vertstrings_list[vertstrings_count++] = sourcestring;
1133         geomstrings_list[geomstrings_count++] = sourcestring;
1134         fragstrings_list[fragstrings_count++] = sourcestring;
1135
1136         // we don't currently use geometry shaders for anything, so just empty the list
1137         geomstrings_count = 0;
1138
1139         // compile the shader program
1140         if (vertstrings_count + geomstrings_count + fragstrings_count)
1141                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1142         if (p->program)
1143         {
1144                 CHECKGLERROR
1145                 qglUseProgram(p->program);CHECKGLERROR
1146                 // look up all the uniform variable names we care about, so we don't
1147                 // have to look them up every time we set them
1148
1149 #if 0
1150                 // debugging aid
1151                 {
1152                         GLint activeuniformindex = 0;
1153                         GLint numactiveuniforms = 0;
1154                         char uniformname[128];
1155                         GLsizei uniformnamelength = 0;
1156                         GLint uniformsize = 0;
1157                         GLenum uniformtype = 0;
1158                         memset(uniformname, 0, sizeof(uniformname));
1159                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1160                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1161                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1162                         {
1163                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1164                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1165                         }
1166                 }
1167 #endif
1168
1169                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1170                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1171                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1172                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1173                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1174                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1175                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1176                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1177                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1178                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1179                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1180                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1181                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1182                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1183                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1184                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1185                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1186                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1187                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1188                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1189                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1190                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1191                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1192                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1193                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1194                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1195                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1196                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1197                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1198                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1199                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1200                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1201                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1202                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1203                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1204                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1205                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1206                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1207                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1208                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1209                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1210                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1211                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1212                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1213                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1214                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1215                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1216                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1217                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1218                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1219                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1220                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1221                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1222                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1223                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1224                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1225                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1226                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1227                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1228                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1229                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1230                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1231                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1232                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1233                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1234                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1235                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1236                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1237                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1238                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1239                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1240                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1241                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1242                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1243                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1244                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1245                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1246                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1247                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1248                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1249                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1250                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1251                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1252                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1253                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1254                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1255                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1256                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1257                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1258                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1259                 // initialize the samplers to refer to the texture units we use
1260                 p->tex_Texture_First = -1;
1261                 p->tex_Texture_Second = -1;
1262                 p->tex_Texture_GammaRamps = -1;
1263                 p->tex_Texture_Normal = -1;
1264                 p->tex_Texture_Color = -1;
1265                 p->tex_Texture_Gloss = -1;
1266                 p->tex_Texture_Glow = -1;
1267                 p->tex_Texture_SecondaryNormal = -1;
1268                 p->tex_Texture_SecondaryColor = -1;
1269                 p->tex_Texture_SecondaryGloss = -1;
1270                 p->tex_Texture_SecondaryGlow = -1;
1271                 p->tex_Texture_Pants = -1;
1272                 p->tex_Texture_Shirt = -1;
1273                 p->tex_Texture_FogHeightTexture = -1;
1274                 p->tex_Texture_FogMask = -1;
1275                 p->tex_Texture_LightGrid = -1;
1276                 p->tex_Texture_Lightmap = -1;
1277                 p->tex_Texture_Deluxemap = -1;
1278                 p->tex_Texture_Attenuation = -1;
1279                 p->tex_Texture_Cube = -1;
1280                 p->tex_Texture_Refraction = -1;
1281                 p->tex_Texture_Reflection = -1;
1282                 p->tex_Texture_ShadowMap2D = -1;
1283                 p->tex_Texture_CubeProjection = -1;
1284                 p->tex_Texture_ScreenNormalMap = -1;
1285                 p->tex_Texture_ScreenDiffuse = -1;
1286                 p->tex_Texture_ScreenSpecular = -1;
1287                 p->tex_Texture_ReflectMask = -1;
1288                 p->tex_Texture_ReflectCube = -1;
1289                 p->tex_Texture_BounceGrid = -1;
1290                 // bind the texture samplers in use
1291                 sampler = 0;
1292                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1293                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1294                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1295                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1296                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1297                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1298                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1299                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1300                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1301                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1302                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1303                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1304                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1305                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1306                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1307                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1308                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1309                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1310                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1311                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1312                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1313                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1314                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1315                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1316                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1317                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1318                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1319                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1320                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1321                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1322                 // get the uniform block indices so we can bind them
1323                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1324 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1325                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1326 #endif
1327                 // clear the uniform block bindings
1328                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1329                 // bind the uniform blocks in use
1330                 ubibind = 0;
1331 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1332                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1333 #endif
1334                 // we're done compiling and setting up the shader, at least until it is used
1335                 CHECKGLERROR
1336                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1337         }
1338         else
1339                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1340
1341         // free the strings
1342         if (sourcestring)
1343                 Mem_Free(sourcestring);
1344 }
1345
1346 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1347 {
1348         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1349         if (r_glsl_permutation != perm)
1350         {
1351                 r_glsl_permutation = perm;
1352                 if (!r_glsl_permutation->program)
1353                 {
1354                         if (!r_glsl_permutation->compiled)
1355                         {
1356                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1357                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1358                         }
1359                         if (!r_glsl_permutation->program)
1360                         {
1361                                 // remove features until we find a valid permutation
1362                                 unsigned i;
1363                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1364                                 {
1365                                         // reduce i more quickly whenever it would not remove any bits
1366                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1367                                         if (!(permutation & j))
1368                                                 continue;
1369                                         permutation -= j;
1370                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1371                                         if (!r_glsl_permutation->compiled)
1372                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1373                                         if (r_glsl_permutation->program)
1374                                                 break;
1375                                 }
1376                                 if (i >= SHADERPERMUTATION_COUNT)
1377                                 {
1378                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1379                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1380                                         qglUseProgram(0);CHECKGLERROR
1381                                         return; // no bit left to clear, entire mode is broken
1382                                 }
1383                         }
1384                 }
1385                 CHECKGLERROR
1386                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1387         }
1388         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1389         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1390         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1391         CHECKGLERROR
1392 }
1393
1394 void R_GLSL_Restart_f(cmd_state_t *cmd)
1395 {
1396         unsigned int i, limit;
1397         switch(vid.renderpath)
1398         {
1399         case RENDERPATH_GL32:
1400         case RENDERPATH_GLES2:
1401                 {
1402                         r_glsl_permutation_t *p;
1403                         r_glsl_permutation = NULL;
1404                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1405                         for (i = 0;i < limit;i++)
1406                         {
1407                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1408                                 {
1409                                         GL_Backend_FreeProgram(p->program);
1410                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1411                                 }
1412                         }
1413                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1414                 }
1415                 break;
1416         }
1417 }
1418
1419 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1420 {
1421         unsigned i;
1422         int language, mode, dupe;
1423         char *text;
1424         shadermodeinfo_t *modeinfo;
1425         qfile_t *file;
1426
1427         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1428         {
1429                 modeinfo = shadermodeinfo[language];
1430                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1431                 {
1432                         // don't dump the same file multiple times (most or all shaders come from the same file)
1433                         for (dupe = mode - 1;dupe >= 0;dupe--)
1434                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1435                                         break;
1436                         if (dupe >= 0)
1437                                 continue;
1438                         text = modeinfo[mode].builtinstring;
1439                         if (!text)
1440                                 continue;
1441                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1442                         if (file)
1443                         {
1444                                 FS_Print(file, "/* The engine may define the following macros:\n");
1445                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1446                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1447                                         FS_Print(file, modeinfo[i].pretext);
1448                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1449                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1450                                 FS_Print(file, "*/\n");
1451                                 FS_Print(file, text);
1452                                 FS_Close(file);
1453                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1454                         }
1455                         else
1456                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1457                 }
1458         }
1459 }
1460
1461 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1462 {
1463         uint64_t permutation = 0;
1464         if (r_trippy.integer && !notrippy)
1465                 permutation |= SHADERPERMUTATION_TRIPPY;
1466         permutation |= SHADERPERMUTATION_VIEWTINT;
1467         if (t)
1468                 permutation |= SHADERPERMUTATION_DIFFUSE;
1469         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1470                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1471         if (suppresstexalpha)
1472                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1473         if (vid.allowalphatocoverage)
1474                 GL_AlphaToCoverage(false);
1475         switch (vid.renderpath)
1476         {
1477         case RENDERPATH_GL32:
1478         case RENDERPATH_GLES2:
1479                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1480                 if (r_glsl_permutation->tex_Texture_First >= 0)
1481                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1482                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1483                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1484                 break;
1485         }
1486 }
1487
1488 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1489 {
1490         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1491 }
1492
1493 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1494 {
1495         uint64_t permutation = 0;
1496         if (r_trippy.integer && !notrippy)
1497                 permutation |= SHADERPERMUTATION_TRIPPY;
1498         if (depthrgb)
1499                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1500         if (skeletal)
1501                 permutation |= SHADERPERMUTATION_SKELETAL;
1502
1503         if (vid.allowalphatocoverage)
1504                 GL_AlphaToCoverage(false);
1505         switch (vid.renderpath)
1506         {
1507         case RENDERPATH_GL32:
1508         case RENDERPATH_GLES2:
1509                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1510 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1511                 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);
1512 #endif
1513                 break;
1514         }
1515 }
1516
1517 #define BLENDFUNC_ALLOWS_COLORMOD      1
1518 #define BLENDFUNC_ALLOWS_FOG           2
1519 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1520 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1521 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1522 static int R_BlendFuncFlags(int src, int dst)
1523 {
1524         int r = 0;
1525
1526         // a blendfunc allows colormod if:
1527         // a) it can never keep the destination pixel invariant, or
1528         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1529         // this is to prevent unintended side effects from colormod
1530
1531         // a blendfunc allows fog if:
1532         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1533         // this is to prevent unintended side effects from fog
1534
1535         // these checks are the output of fogeval.pl
1536
1537         r |= BLENDFUNC_ALLOWS_COLORMOD;
1538         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1539         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1540         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1541         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1542         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1544         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1545         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1546         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1547         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1548         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1549         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1550         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1551         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1552         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1554         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1555         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1556         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1557         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559
1560         return r;
1561 }
1562
1563 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)
1564 {
1565         // select a permutation of the lighting shader appropriate to this
1566         // combination of texture, entity, light source, and fogging, only use the
1567         // minimum features necessary to avoid wasting rendering time in the
1568         // fragment shader on features that are not being used
1569         uint64_t permutation = 0;
1570         unsigned int mode = 0;
1571         int blendfuncflags;
1572         texture_t *t = rsurface.texture;
1573         float m16f[16];
1574         matrix4x4_t tempmatrix;
1575         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1576         if (r_trippy.integer && !notrippy)
1577                 permutation |= SHADERPERMUTATION_TRIPPY;
1578         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1579                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1580         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1581                 permutation |= SHADERPERMUTATION_OCCLUDE;
1582         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1583                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1584         if (rsurfacepass == RSURFPASS_BACKGROUND)
1585         {
1586                 // distorted background
1587                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1588                 {
1589                         mode = SHADERMODE_WATER;
1590                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1591                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1592                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1593                         {
1594                                 // this is the right thing to do for wateralpha
1595                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1596                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1597                         }
1598                         else
1599                         {
1600                                 // this is the right thing to do for entity alpha
1601                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1602                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1603                         }
1604                 }
1605                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1606                 {
1607                         mode = SHADERMODE_REFRACTION;
1608                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1609                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1610                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1611                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1612                 }
1613                 else
1614                 {
1615                         mode = SHADERMODE_GENERIC;
1616                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1617                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1619                 }
1620                 if (vid.allowalphatocoverage)
1621                         GL_AlphaToCoverage(false);
1622         }
1623         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1624         {
1625                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1626                 {
1627                         switch(t->offsetmapping)
1628                         {
1629                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1630                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1631                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1632                         case OFFSETMAPPING_OFF: break;
1633                         }
1634                 }
1635                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1636                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1637                 // normalmap (deferred prepass), may use alpha test on diffuse
1638                 mode = SHADERMODE_DEFERREDGEOMETRY;
1639                 GL_BlendFunc(GL_ONE, GL_ZERO);
1640                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1641                 if (vid.allowalphatocoverage)
1642                         GL_AlphaToCoverage(false);
1643         }
1644         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1645         {
1646                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1647                 {
1648                         switch(t->offsetmapping)
1649                         {
1650                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1651                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1652                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1653                         case OFFSETMAPPING_OFF: break;
1654                         }
1655                 }
1656                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1657                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1658                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1659                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1660                 // light source
1661                 mode = SHADERMODE_LIGHTSOURCE;
1662                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1663                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1664                 if (VectorLength2(rtlightdiffuse) > 0)
1665                         permutation |= SHADERPERMUTATION_DIFFUSE;
1666                 if (VectorLength2(rtlightspecular) > 0)
1667                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1668                 if (r_refdef.fogenabled)
1669                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1670                 if (t->colormapping)
1671                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1672                 if (r_shadow_usingshadowmap2d)
1673                 {
1674                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1675                         if(r_shadow_shadowmapvsdct)
1676                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1677
1678                         if (r_shadow_shadowmap2ddepthbuffer)
1679                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1680                 }
1681                 if (t->reflectmasktexture)
1682                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1683                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1684                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1685                 if (vid.allowalphatocoverage)
1686                         GL_AlphaToCoverage(false);
1687         }
1688         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1689         {
1690                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1691                 {
1692                         switch(t->offsetmapping)
1693                         {
1694                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1695                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1696                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1697                         case OFFSETMAPPING_OFF: break;
1698                         }
1699                 }
1700                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1701                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1702                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1703                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1704                 // directional model lighting
1705                 mode = SHADERMODE_LIGHTGRID;
1706                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1707                         permutation |= SHADERPERMUTATION_GLOW;
1708                 permutation |= SHADERPERMUTATION_DIFFUSE;
1709                 if (t->glosstexture || t->backgroundglosstexture)
1710                         permutation |= SHADERPERMUTATION_SPECULAR;
1711                 if (r_refdef.fogenabled)
1712                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1713                 if (t->colormapping)
1714                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1715                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1716                 {
1717                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1718                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1719
1720                         if (r_shadow_shadowmap2ddepthbuffer)
1721                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1722                 }
1723                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1724                         permutation |= SHADERPERMUTATION_REFLECTION;
1725                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1726                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1727                 if (t->reflectmasktexture)
1728                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1729                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1730                 {
1731                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1732                         if (r_shadow_bouncegrid_state.directional)
1733                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1734                 }
1735                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1736                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1737                 // when using alphatocoverage, we don't need alphakill
1738                 if (vid.allowalphatocoverage)
1739                 {
1740                         if (r_transparent_alphatocoverage.integer)
1741                         {
1742                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1743                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1744                         }
1745                         else
1746                                 GL_AlphaToCoverage(false);
1747                 }
1748         }
1749         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1750         {
1751                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1752                 {
1753                         switch(t->offsetmapping)
1754                         {
1755                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1756                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1757                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1758                         case OFFSETMAPPING_OFF: break;
1759                         }
1760                 }
1761                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1762                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1763                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1764                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1765                 // directional model lighting
1766                 mode = SHADERMODE_LIGHTDIRECTION;
1767                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1768                         permutation |= SHADERPERMUTATION_GLOW;
1769                 if (VectorLength2(t->render_modellight_diffuse))
1770                         permutation |= SHADERPERMUTATION_DIFFUSE;
1771                 if (VectorLength2(t->render_modellight_specular) > 0)
1772                         permutation |= SHADERPERMUTATION_SPECULAR;
1773                 if (r_refdef.fogenabled)
1774                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1775                 if (t->colormapping)
1776                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1777                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1778                 {
1779                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1780                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1781
1782                         if (r_shadow_shadowmap2ddepthbuffer)
1783                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1784                 }
1785                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1786                         permutation |= SHADERPERMUTATION_REFLECTION;
1787                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1788                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1789                 if (t->reflectmasktexture)
1790                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1791                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1792                 {
1793                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1794                         if (r_shadow_bouncegrid_state.directional)
1795                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1796                 }
1797                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1798                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1799                 // when using alphatocoverage, we don't need alphakill
1800                 if (vid.allowalphatocoverage)
1801                 {
1802                         if (r_transparent_alphatocoverage.integer)
1803                         {
1804                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1805                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1806                         }
1807                         else
1808                                 GL_AlphaToCoverage(false);
1809                 }
1810         }
1811         else
1812         {
1813                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1814                 {
1815                         switch(t->offsetmapping)
1816                         {
1817                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1818                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1819                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1820                         case OFFSETMAPPING_OFF: break;
1821                         }
1822                 }
1823                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1824                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1825                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1826                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1827                 // lightmapped wall
1828                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1829                         permutation |= SHADERPERMUTATION_GLOW;
1830                 if (r_refdef.fogenabled && !ui)
1831                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1832                 if (t->colormapping)
1833                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1834                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1835                 {
1836                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1837                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1838
1839                         if (r_shadow_shadowmap2ddepthbuffer)
1840                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1841                 }
1842                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1843                         permutation |= SHADERPERMUTATION_REFLECTION;
1844                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1845                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1846                 if (t->reflectmasktexture)
1847                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1848                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1849                 {
1850                         // deluxemapping (light direction texture)
1851                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1852                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1853                         else
1854                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1855                         permutation |= SHADERPERMUTATION_DIFFUSE;
1856                         if (VectorLength2(t->render_lightmap_specular) > 0)
1857                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1858                 }
1859                 else if (r_glsl_deluxemapping.integer >= 2)
1860                 {
1861                         // fake deluxemapping (uniform light direction in tangentspace)
1862                         if (rsurface.uselightmaptexture)
1863                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1864                         else
1865                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1866                         permutation |= SHADERPERMUTATION_DIFFUSE;
1867                         if (VectorLength2(t->render_lightmap_specular) > 0)
1868                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1869                 }
1870                 else if (rsurface.uselightmaptexture)
1871                 {
1872                         // ordinary lightmapping (q1bsp, q3bsp)
1873                         mode = SHADERMODE_LIGHTMAP;
1874                 }
1875                 else
1876                 {
1877                         // ordinary vertex coloring (q3bsp)
1878                         mode = SHADERMODE_VERTEXCOLOR;
1879                 }
1880                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1881                 {
1882                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1883                         if (r_shadow_bouncegrid_state.directional)
1884                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1885                 }
1886                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1887                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1888                 // when using alphatocoverage, we don't need alphakill
1889                 if (vid.allowalphatocoverage)
1890                 {
1891                         if (r_transparent_alphatocoverage.integer)
1892                         {
1893                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1894                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1895                         }
1896                         else
1897                                 GL_AlphaToCoverage(false);
1898                 }
1899         }
1900         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1901                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1902         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1903                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1904         switch(vid.renderpath)
1905         {
1906         case RENDERPATH_GL32:
1907         case RENDERPATH_GLES2:
1908                 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);
1909                 RSurf_UploadBuffersForBatch();
1910                 // this has to be after RSurf_PrepareVerticesForBatch
1911                 if (rsurface.batchskeletaltransform3x4buffer)
1912                         permutation |= SHADERPERMUTATION_SKELETAL;
1913                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1914 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1915                 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);
1916 #endif
1917                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1918                 if (mode == SHADERMODE_LIGHTSOURCE)
1919                 {
1920                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1921                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1922                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1923                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1924                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1925                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1926
1927                         // additive passes are only darkened by fog, not tinted
1928                         if (r_glsl_permutation->loc_FogColor >= 0)
1929                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1930                         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);
1931                 }
1932                 else
1933                 {
1934                         if (mode == SHADERMODE_FLATCOLOR)
1935                         {
1936                                 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]);
1937                         }
1938                         else if (mode == SHADERMODE_LIGHTGRID)
1939                         {
1940                                 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]);
1941                                 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]);
1942                                 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]);
1943                                 // other LightGrid uniforms handled below
1944                         }
1945                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1946                         {
1947                                 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]);
1948                                 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]);
1949                                 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]);
1950                                 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]);
1951                                 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]);
1952                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1953                                 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]);
1954                         }
1955                         else
1956                         {
1957                                 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]);
1958                                 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]);
1959                                 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]);
1960                                 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]);
1961                                 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]);
1962                         }
1963                         // additive passes are only darkened by fog, not tinted
1964                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1965                         {
1966                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1967                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1968                                 else
1969                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1970                         }
1971                         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);
1972                         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]);
1973                         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]);
1974                         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);
1975                         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);
1976                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1977                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1978                         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);
1979                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1980                 }
1981                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1982                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1983                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1984                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1985                 {
1986                         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]);
1987                         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]);
1988                 }
1989                 else
1990                 {
1991                         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]);
1992                         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]);
1993                 }
1994
1995                 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]);
1996                 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));
1997                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1998                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1999                 {
2000                         if (t->pantstexture)
2001                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2002                         else
2003                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2004                 }
2005                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2006                 {
2007                         if (t->shirttexture)
2008                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2009                         else
2010                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2011                 }
2012                 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]);
2013                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2014                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2015                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2016                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2017                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2018                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2019                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2020                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2021                         );
2022                 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);
2023                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2024                 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]);
2025                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2026                 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);}
2027                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2028                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2029                 {
2030                         float m9f[9];
2031                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2032                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2033                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2034                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2035                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2036                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2037                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2038                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2039                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2040                 }
2041
2042                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2043                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2044                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2045                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2046                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2047                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2048                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2049                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2050                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2051                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2052                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2053                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2054                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2055                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2056                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2057                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2058                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2059                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2060                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2061                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2062                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2063                 {
2064                         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);
2065                         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);
2066                         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);
2067                 }
2068                 else
2069                 {
2070                         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);
2071                 }
2072                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2073                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2074                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2075                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2076                 {
2077                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2078                         if (rsurface.rtlight)
2079                         {
2080                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2081                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2082                         }
2083                 }
2084                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2085                 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);
2086                 CHECKGLERROR
2087                 break;
2088         }
2089 }
2090
2091 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2092 {
2093         // select a permutation of the lighting shader appropriate to this
2094         // combination of texture, entity, light source, and fogging, only use the
2095         // minimum features necessary to avoid wasting rendering time in the
2096         // fragment shader on features that are not being used
2097         uint64_t permutation = 0;
2098         unsigned int mode = 0;
2099         const float *lightcolorbase = rtlight->currentcolor;
2100         float ambientscale = rtlight->ambientscale;
2101         float diffusescale = rtlight->diffusescale;
2102         float specularscale = rtlight->specularscale;
2103         // this is the location of the light in view space
2104         vec3_t viewlightorigin;
2105         // this transforms from view space (camera) to light space (cubemap)
2106         matrix4x4_t viewtolight;
2107         matrix4x4_t lighttoview;
2108         float viewtolight16f[16];
2109         // light source
2110         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2111         if (rtlight->currentcubemap != r_texture_whitecube)
2112                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2113         if (diffusescale > 0)
2114                 permutation |= SHADERPERMUTATION_DIFFUSE;
2115         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2116                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2117         if (r_shadow_usingshadowmap2d)
2118         {
2119                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2120                 if (r_shadow_shadowmapvsdct)
2121                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2122
2123                 if (r_shadow_shadowmap2ddepthbuffer)
2124                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2125         }
2126         if (vid.allowalphatocoverage)
2127                 GL_AlphaToCoverage(false);
2128         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2129         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2130         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2131         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2132         switch(vid.renderpath)
2133         {
2134         case RENDERPATH_GL32:
2135         case RENDERPATH_GLES2:
2136                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2137                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2138                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2139                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2140                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2141                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2142                 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]);
2143                 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]);
2144                 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);
2145                 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]);
2146                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2147
2148                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2149                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2150                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2151                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2152                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2153                 break;
2154         }
2155 }
2156
2157 #define SKINFRAME_HASH 1024
2158
2159 typedef struct
2160 {
2161         unsigned int loadsequence; // incremented each level change
2162         memexpandablearray_t array;
2163         skinframe_t *hash[SKINFRAME_HASH];
2164 }
2165 r_skinframe_t;
2166 r_skinframe_t r_skinframe;
2167
2168 void R_SkinFrame_PrepareForPurge(void)
2169 {
2170         r_skinframe.loadsequence++;
2171         // wrap it without hitting zero
2172         if (r_skinframe.loadsequence >= 200)
2173                 r_skinframe.loadsequence = 1;
2174 }
2175
2176 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2177 {
2178         if (!skinframe)
2179                 return;
2180         // mark the skinframe as used for the purging code
2181         skinframe->loadsequence = r_skinframe.loadsequence;
2182 }
2183
2184 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2185 {
2186         if (s == NULL)
2187                 return;
2188         if (s->merged == s->base)
2189                 s->merged = NULL;
2190         R_PurgeTexture(s->stain); s->stain = NULL;
2191         R_PurgeTexture(s->merged); s->merged = NULL;
2192         R_PurgeTexture(s->base); s->base = NULL;
2193         R_PurgeTexture(s->pants); s->pants = NULL;
2194         R_PurgeTexture(s->shirt); s->shirt = NULL;
2195         R_PurgeTexture(s->nmap); s->nmap = NULL;
2196         R_PurgeTexture(s->gloss); s->gloss = NULL;
2197         R_PurgeTexture(s->glow); s->glow = NULL;
2198         R_PurgeTexture(s->fog); s->fog = NULL;
2199         R_PurgeTexture(s->reflect); s->reflect = NULL;
2200         s->loadsequence = 0;
2201 }
2202
2203 void R_SkinFrame_Purge(void)
2204 {
2205         int i;
2206         skinframe_t *s;
2207         for (i = 0;i < SKINFRAME_HASH;i++)
2208         {
2209                 for (s = r_skinframe.hash[i];s;s = s->next)
2210                 {
2211                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2212                                 R_SkinFrame_PurgeSkinFrame(s);
2213                 }
2214         }
2215 }
2216
2217 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2218         skinframe_t *item;
2219         char basename[MAX_QPATH];
2220
2221         Image_StripImageExtension(name, basename, sizeof(basename));
2222
2223         if( last == NULL ) {
2224                 int hashindex;
2225                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2226                 item = r_skinframe.hash[hashindex];
2227         } else {
2228                 item = last->next;
2229         }
2230
2231         // linearly search through the hash bucket
2232         for( ; item ; item = item->next ) {
2233                 if( !strcmp( item->basename, basename ) ) {
2234                         return item;
2235                 }
2236         }
2237         return NULL;
2238 }
2239
2240 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2241 {
2242         skinframe_t *item;
2243         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2244         int hashindex;
2245         char basename[MAX_QPATH];
2246
2247         Image_StripImageExtension(name, basename, sizeof(basename));
2248
2249         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2250         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2251                 if (!strcmp(item->basename, basename) &&
2252                         item->textureflags == compareflags &&
2253                         item->comparewidth == comparewidth &&
2254                         item->compareheight == compareheight &&
2255                         item->comparecrc == comparecrc)
2256                         break;
2257
2258         if (!item)
2259         {
2260                 if (!add)
2261                         return NULL;
2262                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2263                 memset(item, 0, sizeof(*item));
2264                 dp_strlcpy(item->basename, basename, sizeof(item->basename));
2265                 item->textureflags = compareflags;
2266                 item->comparewidth = comparewidth;
2267                 item->compareheight = compareheight;
2268                 item->comparecrc = comparecrc;
2269                 item->next = r_skinframe.hash[hashindex];
2270                 r_skinframe.hash[hashindex] = item;
2271         }
2272         else if (textureflags & TEXF_FORCE_RELOAD)
2273                 R_SkinFrame_PurgeSkinFrame(item);
2274
2275         R_SkinFrame_MarkUsed(item);
2276         return item;
2277 }
2278
2279 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2280         { \
2281                 unsigned long long avgcolor[5], wsum; \
2282                 int pix, comp, w; \
2283                 avgcolor[0] = 0; \
2284                 avgcolor[1] = 0; \
2285                 avgcolor[2] = 0; \
2286                 avgcolor[3] = 0; \
2287                 avgcolor[4] = 0; \
2288                 wsum = 0; \
2289                 for(pix = 0; pix < cnt; ++pix) \
2290                 { \
2291                         w = 0; \
2292                         for(comp = 0; comp < 3; ++comp) \
2293                                 w += getpixel; \
2294                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2295                         { \
2296                                 ++wsum; \
2297                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2298                                 w = getpixel; \
2299                                 for(comp = 0; comp < 3; ++comp) \
2300                                         avgcolor[comp] += getpixel * w; \
2301                                 avgcolor[3] += w; \
2302                         } \
2303                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2304                         avgcolor[4] += getpixel; \
2305                 } \
2306                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2307                         avgcolor[3] = 1; \
2308                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2309                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2310                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2311                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2312         }
2313
2314 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2315 {
2316         skinframe_t *skinframe;
2317
2318         if (cls.state == ca_dedicated)
2319                 return NULL;
2320
2321         // return an existing skinframe if already loaded
2322         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2323         if (skinframe && skinframe->base)
2324                 return skinframe;
2325
2326         // if the skinframe doesn't exist this will create it
2327         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2328 }
2329
2330 extern cvar_t gl_picmip;
2331 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2332 {
2333         int j;
2334         unsigned char *pixels;
2335         unsigned char *bumppixels;
2336         unsigned char *basepixels = NULL;
2337         int basepixels_width = 0;
2338         int basepixels_height = 0;
2339         rtexture_t *ddsbase = NULL;
2340         qbool ddshasalpha = false;
2341         float ddsavgcolor[4];
2342         char basename[MAX_QPATH];
2343         int miplevel = R_PicmipForFlags(textureflags);
2344         int savemiplevel = miplevel;
2345         int mymiplevel;
2346         char vabuf[1024];
2347
2348         if (cls.state == ca_dedicated)
2349                 return NULL;
2350
2351         Image_StripImageExtension(name, basename, sizeof(basename));
2352
2353         // check for DDS texture file first
2354         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2355         {
2356                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2357                 if (basepixels == NULL && fallbacknotexture)
2358                         basepixels = Image_GenerateNoTexture();
2359                 if (basepixels == NULL)
2360                         return NULL;
2361         }
2362
2363         // FIXME handle miplevel
2364
2365         if (developer_loading.integer)
2366                 Con_Printf("loading skin \"%s\"\n", name);
2367
2368         // we've got some pixels to store, so really allocate this new texture now
2369         if (!skinframe)
2370                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2371         textureflags &= ~TEXF_FORCE_RELOAD;
2372         skinframe->stain = NULL;
2373         skinframe->merged = NULL;
2374         skinframe->base = NULL;
2375         skinframe->pants = NULL;
2376         skinframe->shirt = NULL;
2377         skinframe->nmap = NULL;
2378         skinframe->gloss = NULL;
2379         skinframe->glow = NULL;
2380         skinframe->fog = NULL;
2381         skinframe->reflect = NULL;
2382         skinframe->hasalpha = false;
2383         // we could store the q2animname here too
2384
2385         if (ddsbase)
2386         {
2387                 skinframe->base = ddsbase;
2388                 skinframe->hasalpha = ddshasalpha;
2389                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2390                 if (r_loadfog && skinframe->hasalpha)
2391                         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);
2392                 //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]);
2393         }
2394         else
2395         {
2396                 basepixels_width = image_width;
2397                 basepixels_height = image_height;
2398                 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);
2399                 if (textureflags & TEXF_ALPHA)
2400                 {
2401                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2402                         {
2403                                 if (basepixels[j] < 255)
2404                                 {
2405                                         skinframe->hasalpha = true;
2406                                         break;
2407                                 }
2408                         }
2409                         if (r_loadfog && skinframe->hasalpha)
2410                         {
2411                                 // has transparent pixels
2412                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2413                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2414                                 {
2415                                         pixels[j+0] = 255;
2416                                         pixels[j+1] = 255;
2417                                         pixels[j+2] = 255;
2418                                         pixels[j+3] = basepixels[j+3];
2419                                 }
2420                                 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);
2421                                 Mem_Free(pixels);
2422                         }
2423                 }
2424                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2425 #ifndef USE_GLES2
2426                 //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]);
2427                 if (r_savedds && skinframe->base)
2428                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2429                 if (r_savedds && skinframe->fog)
2430                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2431 #endif
2432         }
2433
2434         if (r_loaddds)
2435         {
2436                 mymiplevel = savemiplevel;
2437                 if (r_loadnormalmap)
2438                         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);
2439                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2440                 if (r_loadgloss)
2441                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2442                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2443                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2444                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2445         }
2446
2447         // _norm is the name used by tenebrae and has been adopted as standard
2448         if (r_loadnormalmap && skinframe->nmap == NULL)
2449         {
2450                 mymiplevel = savemiplevel;
2451                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2452                 {
2453                         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);
2454                         Mem_Free(pixels);
2455                         pixels = NULL;
2456                 }
2457                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2458                 {
2459                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2460                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2461                         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);
2462                         Mem_Free(pixels);
2463                         Mem_Free(bumppixels);
2464                 }
2465                 else if (r_shadow_bumpscale_basetexture.value > 0)
2466                 {
2467                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2468                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2469                         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);
2470                         Mem_Free(pixels);
2471                 }
2472 #ifndef USE_GLES2
2473                 if (r_savedds && skinframe->nmap)
2474                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2475 #endif
2476         }
2477
2478         // _luma is supported only for tenebrae compatibility
2479         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2480         // _glow is the preferred name
2481         mymiplevel = savemiplevel;
2482         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))))
2483         {
2484                 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);
2485 #ifndef USE_GLES2
2486                 if (r_savedds && skinframe->glow)
2487                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2488 #endif
2489                 Mem_Free(pixels);pixels = NULL;
2490         }
2491
2492         mymiplevel = savemiplevel;
2493         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2494         {
2495                 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);
2496 #ifndef USE_GLES2
2497                 if (r_savedds && skinframe->gloss)
2498                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2499 #endif
2500                 Mem_Free(pixels);
2501                 pixels = NULL;
2502         }
2503
2504         mymiplevel = savemiplevel;
2505         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2506         {
2507                 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);
2508 #ifndef USE_GLES2
2509                 if (r_savedds && skinframe->pants)
2510                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2511 #endif
2512                 Mem_Free(pixels);
2513                 pixels = NULL;
2514         }
2515
2516         mymiplevel = savemiplevel;
2517         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2518         {
2519                 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);
2520 #ifndef USE_GLES2
2521                 if (r_savedds && skinframe->shirt)
2522                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2523 #endif
2524                 Mem_Free(pixels);
2525                 pixels = NULL;
2526         }
2527
2528         mymiplevel = savemiplevel;
2529         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2530         {
2531                 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);
2532 #ifndef USE_GLES2
2533                 if (r_savedds && skinframe->reflect)
2534                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2535 #endif
2536                 Mem_Free(pixels);
2537                 pixels = NULL;
2538         }
2539
2540         if (basepixels)
2541                 Mem_Free(basepixels);
2542
2543         return skinframe;
2544 }
2545
2546 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)
2547 {
2548         int i;
2549         skinframe_t *skinframe;
2550         char vabuf[1024];
2551
2552         if (cls.state == ca_dedicated)
2553                 return NULL;
2554
2555         // if already loaded just return it, otherwise make a new skinframe
2556         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2557         if (skinframe->base)
2558                 return skinframe;
2559         textureflags &= ~TEXF_FORCE_RELOAD;
2560
2561         skinframe->stain = NULL;
2562         skinframe->merged = NULL;
2563         skinframe->base = NULL;
2564         skinframe->pants = NULL;
2565         skinframe->shirt = NULL;
2566         skinframe->nmap = NULL;
2567         skinframe->gloss = NULL;
2568         skinframe->glow = NULL;
2569         skinframe->fog = NULL;
2570         skinframe->reflect = NULL;
2571         skinframe->hasalpha = false;
2572
2573         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2574         if (!skindata)
2575                 return NULL;
2576
2577         if (developer_loading.integer)
2578                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2579
2580         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2581         {
2582                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2583                 unsigned char *b = a + width * height * 4;
2584                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2585                 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);
2586                 Mem_Free(a);
2587         }
2588         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2589         if (textureflags & TEXF_ALPHA)
2590         {
2591                 for (i = 3;i < width * height * 4;i += 4)
2592                 {
2593                         if (skindata[i] < 255)
2594                         {
2595                                 skinframe->hasalpha = true;
2596                                 break;
2597                         }
2598                 }
2599                 if (r_loadfog && skinframe->hasalpha)
2600                 {
2601                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2602                         memcpy(fogpixels, skindata, width * height * 4);
2603                         for (i = 0;i < width * height * 4;i += 4)
2604                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2605                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2606                         Mem_Free(fogpixels);
2607                 }
2608         }
2609
2610         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2611         //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]);
2612
2613         return skinframe;
2614 }
2615
2616 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2617 {
2618         int i;
2619         int featuresmask;
2620         skinframe_t *skinframe;
2621
2622         if (cls.state == ca_dedicated)
2623                 return NULL;
2624
2625         // if already loaded just return it, otherwise make a new skinframe
2626         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2627         if (skinframe->base)
2628                 return skinframe;
2629         //textureflags &= ~TEXF_FORCE_RELOAD;
2630
2631         skinframe->stain = NULL;
2632         skinframe->merged = NULL;
2633         skinframe->base = NULL;
2634         skinframe->pants = NULL;
2635         skinframe->shirt = NULL;
2636         skinframe->nmap = NULL;
2637         skinframe->gloss = NULL;
2638         skinframe->glow = NULL;
2639         skinframe->fog = NULL;
2640         skinframe->reflect = NULL;
2641         skinframe->hasalpha = false;
2642
2643         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2644         if (!skindata)
2645                 return NULL;
2646
2647         if (developer_loading.integer)
2648                 Con_Printf("loading quake skin \"%s\"\n", name);
2649
2650         // 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)
2651         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2652         memcpy(skinframe->qpixels, skindata, width*height);
2653         skinframe->qwidth = width;
2654         skinframe->qheight = height;
2655
2656         featuresmask = 0;
2657         for (i = 0;i < width * height;i++)
2658                 featuresmask |= palette_featureflags[skindata[i]];
2659
2660         skinframe->hasalpha = false;
2661         // fence textures
2662         if (name[0] == '{')
2663                 skinframe->hasalpha = true;
2664         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2665         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2666         skinframe->qgeneratemerged = true;
2667         skinframe->qgeneratebase = skinframe->qhascolormapping;
2668         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2669
2670         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2671         //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]);
2672
2673         return skinframe;
2674 }
2675
2676 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2677 {
2678         int width;
2679         int height;
2680         unsigned char *skindata;
2681         char vabuf[1024];
2682
2683         if (!skinframe->qpixels)
2684                 return;
2685
2686         if (!skinframe->qhascolormapping)
2687                 colormapped = false;
2688
2689         if (colormapped)
2690         {
2691                 if (!skinframe->qgeneratebase)
2692                         return;
2693         }
2694         else
2695         {
2696                 if (!skinframe->qgeneratemerged)
2697                         return;
2698         }
2699
2700         width = skinframe->qwidth;
2701         height = skinframe->qheight;
2702         skindata = skinframe->qpixels;
2703
2704         if (skinframe->qgeneratenmap)
2705         {
2706                 unsigned char *a, *b;
2707                 skinframe->qgeneratenmap = false;
2708                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2709                 b = a + width * height * 4;
2710                 // use either a custom palette or the quake palette
2711                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2712                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2713                 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);
2714                 Mem_Free(a);
2715         }
2716
2717         if (skinframe->qgenerateglow)
2718         {
2719                 skinframe->qgenerateglow = false;
2720                 if (skinframe->hasalpha) // fence textures
2721                         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
2722                 else
2723                         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
2724         }
2725
2726         if (colormapped)
2727         {
2728                 skinframe->qgeneratebase = false;
2729                 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);
2730                 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);
2731                 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);
2732         }
2733         else
2734         {
2735                 skinframe->qgeneratemerged = false;
2736                 if (skinframe->hasalpha) // fence textures
2737                         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);
2738                 else
2739                         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);
2740         }
2741
2742         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2743         {
2744                 Mem_Free(skinframe->qpixels);
2745                 skinframe->qpixels = NULL;
2746         }
2747 }
2748
2749 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)
2750 {
2751         int i;
2752         skinframe_t *skinframe;
2753         char vabuf[1024];
2754
2755         if (cls.state == ca_dedicated)
2756                 return NULL;
2757
2758         // if already loaded just return it, otherwise make a new skinframe
2759         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2760         if (skinframe->base)
2761                 return skinframe;
2762         textureflags &= ~TEXF_FORCE_RELOAD;
2763
2764         skinframe->stain = NULL;
2765         skinframe->merged = NULL;
2766         skinframe->base = NULL;
2767         skinframe->pants = NULL;
2768         skinframe->shirt = NULL;
2769         skinframe->nmap = NULL;
2770         skinframe->gloss = NULL;
2771         skinframe->glow = NULL;
2772         skinframe->fog = NULL;
2773         skinframe->reflect = NULL;
2774         skinframe->hasalpha = false;
2775
2776         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2777         if (!skindata)
2778                 return NULL;
2779
2780         if (developer_loading.integer)
2781                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2782
2783         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2784         if ((textureflags & TEXF_ALPHA) && alphapalette)
2785         {
2786                 for (i = 0;i < width * height;i++)
2787                 {
2788                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2789                         {
2790                                 skinframe->hasalpha = true;
2791                                 break;
2792                         }
2793                 }
2794                 if (r_loadfog && skinframe->hasalpha)
2795                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2796         }
2797
2798         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2799         //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]);
2800
2801         return skinframe;
2802 }
2803
2804 skinframe_t *R_SkinFrame_LoadMissing(void)
2805 {
2806         skinframe_t *skinframe;
2807
2808         if (cls.state == ca_dedicated)
2809                 return NULL;
2810
2811         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2812         skinframe->stain = NULL;
2813         skinframe->merged = NULL;
2814         skinframe->base = NULL;
2815         skinframe->pants = NULL;
2816         skinframe->shirt = NULL;
2817         skinframe->nmap = NULL;
2818         skinframe->gloss = NULL;
2819         skinframe->glow = NULL;
2820         skinframe->fog = NULL;
2821         skinframe->reflect = NULL;
2822         skinframe->hasalpha = false;
2823
2824         skinframe->avgcolor[0] = rand() / RAND_MAX;
2825         skinframe->avgcolor[1] = rand() / RAND_MAX;
2826         skinframe->avgcolor[2] = rand() / RAND_MAX;
2827         skinframe->avgcolor[3] = 1;
2828
2829         return skinframe;
2830 }
2831
2832 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2833 {
2834         if (cls.state == ca_dedicated)
2835                 return NULL;
2836
2837         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2838 }
2839
2840 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2841 {
2842         skinframe_t *skinframe;
2843         if (cls.state == ca_dedicated)
2844                 return NULL;
2845         // if already loaded just return it, otherwise make a new skinframe
2846         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2847         if (skinframe->base)
2848                 return skinframe;
2849         textureflags &= ~TEXF_FORCE_RELOAD;
2850         skinframe->stain = NULL;
2851         skinframe->merged = NULL;
2852         skinframe->base = NULL;
2853         skinframe->pants = NULL;
2854         skinframe->shirt = NULL;
2855         skinframe->nmap = NULL;
2856         skinframe->gloss = NULL;
2857         skinframe->glow = NULL;
2858         skinframe->fog = NULL;
2859         skinframe->reflect = NULL;
2860         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2861         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2862         if (!tex)
2863                 return NULL;
2864         if (developer_loading.integer)
2865                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2866         skinframe->base = skinframe->merged = tex;
2867         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2868         return skinframe;
2869 }
2870
2871 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2872 typedef struct suffixinfo_s
2873 {
2874         const char *suffix;
2875         qbool flipx, flipy, flipdiagonal;
2876 }
2877 suffixinfo_t;
2878 static suffixinfo_t suffix[3][6] =
2879 {
2880         {
2881                 {"px",   false, false, false},
2882                 {"nx",   false, false, false},
2883                 {"py",   false, false, false},
2884                 {"ny",   false, false, false},
2885                 {"pz",   false, false, false},
2886                 {"nz",   false, false, false}
2887         },
2888         {
2889                 {"posx", false, false, false},
2890                 {"negx", false, false, false},
2891                 {"posy", false, false, false},
2892                 {"negy", false, false, false},
2893                 {"posz", false, false, false},
2894                 {"negz", false, false, false}
2895         },
2896         {
2897                 {"rt",    true, false,  true},
2898                 {"lf",   false,  true,  true},
2899                 {"ft",    true,  true, false},
2900                 {"bk",   false, false, false},
2901                 {"up",    true, false,  true},
2902                 {"dn",    true, false,  true}
2903         }
2904 };
2905
2906 static int componentorder[4] = {0, 1, 2, 3};
2907
2908 static rtexture_t *R_LoadCubemap(const char *basename)
2909 {
2910         int i, j, cubemapsize, forcefilter;
2911         unsigned char *cubemappixels, *image_buffer;
2912         rtexture_t *cubemaptexture;
2913         char name[256];
2914
2915         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2916         forcefilter = TEXF_FORCELINEAR;
2917         if (basename && basename[0] == '!')
2918         {
2919                 basename++;
2920                 forcefilter = TEXF_FORCENEAREST;
2921         }
2922         // must start 0 so the first loadimagepixels has no requested width/height
2923         cubemapsize = 0;
2924         cubemappixels = NULL;
2925         cubemaptexture = NULL;
2926         // keep trying different suffix groups (posx, px, rt) until one loads
2927         for (j = 0;j < 3 && !cubemappixels;j++)
2928         {
2929                 // load the 6 images in the suffix group
2930                 for (i = 0;i < 6;i++)
2931                 {
2932                         // generate an image name based on the base and and suffix
2933                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2934                         // load it
2935                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2936                         {
2937                                 // an image loaded, make sure width and height are equal
2938                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2939                                 {
2940                                         // if this is the first image to load successfully, allocate the cubemap memory
2941                                         if (!cubemappixels && image_width >= 1)
2942                                         {
2943                                                 cubemapsize = image_width;
2944                                                 // note this clears to black, so unavailable sides are black
2945                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2946                                         }
2947                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2948                                         if (cubemappixels)
2949                                                 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);
2950                                 }
2951                                 else
2952                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2953                                 // free the image
2954                                 Mem_Free(image_buffer);
2955                         }
2956                 }
2957         }
2958         // if a cubemap loaded, upload it
2959         if (cubemappixels)
2960         {
2961                 if (developer_loading.integer)
2962                         Con_Printf("loading cubemap \"%s\"\n", basename);
2963
2964                 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);
2965                 Mem_Free(cubemappixels);
2966         }
2967         else
2968         {
2969                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2970                 if (developer_loading.integer)
2971                 {
2972                         Con_Printf("(tried tried images ");
2973                         for (j = 0;j < 3;j++)
2974                                 for (i = 0;i < 6;i++)
2975                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2976                         Con_Print(" and was unable to find any of them).\n");
2977                 }
2978         }
2979         return cubemaptexture;
2980 }
2981
2982 rtexture_t *R_GetCubemap(const char *basename)
2983 {
2984         int i;
2985         for (i = 0;i < r_texture_numcubemaps;i++)
2986                 if (r_texture_cubemaps[i] != NULL)
2987                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2988                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2989         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2990                 return r_texture_whitecube;
2991         r_texture_numcubemaps++;
2992         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2993         dp_strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2994         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2995         return r_texture_cubemaps[i]->texture;
2996 }
2997
2998 static void R_Main_FreeViewCache(void)
2999 {
3000         if (r_refdef.viewcache.entityvisible)
3001                 Mem_Free(r_refdef.viewcache.entityvisible);
3002         if (r_refdef.viewcache.world_pvsbits)
3003                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3004         if (r_refdef.viewcache.world_leafvisible)
3005                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3006         if (r_refdef.viewcache.world_surfacevisible)
3007                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3008         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3009 }
3010
3011 static void R_Main_ResizeViewCache(void)
3012 {
3013         int numentities = r_refdef.scene.numentities;
3014         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3015         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3016         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3017         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3018         if (r_refdef.viewcache.maxentities < numentities)
3019         {
3020                 r_refdef.viewcache.maxentities = numentities;
3021                 if (r_refdef.viewcache.entityvisible)
3022                         Mem_Free(r_refdef.viewcache.entityvisible);
3023                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3024         }
3025         if (r_refdef.viewcache.world_numclusters != numclusters)
3026         {
3027                 r_refdef.viewcache.world_numclusters = numclusters;
3028                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3029                 if (r_refdef.viewcache.world_pvsbits)
3030                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3031                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3032         }
3033         if (r_refdef.viewcache.world_numleafs != numleafs)
3034         {
3035                 r_refdef.viewcache.world_numleafs = numleafs;
3036                 if (r_refdef.viewcache.world_leafvisible)
3037                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3038                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3039         }
3040         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3041         {
3042                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3043                 if (r_refdef.viewcache.world_surfacevisible)
3044                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3045                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3046         }
3047 }
3048
3049 extern rtexture_t *loadingscreentexture;
3050 static void gl_main_start(void)
3051 {
3052         loadingscreentexture = NULL;
3053         r_texture_blanknormalmap = NULL;
3054         r_texture_white = NULL;
3055         r_texture_grey128 = NULL;
3056         r_texture_black = NULL;
3057         r_texture_whitecube = NULL;
3058         r_texture_normalizationcube = NULL;
3059         r_texture_fogattenuation = NULL;
3060         r_texture_fogheighttexture = NULL;
3061         r_texture_gammaramps = NULL;
3062         r_texture_numcubemaps = 0;
3063         r_uniformbufferalignment = 32;
3064
3065         r_loaddds = r_texture_dds_load.integer != 0;
3066         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3067
3068         switch(vid.renderpath)
3069         {
3070         case RENDERPATH_GL32:
3071         case RENDERPATH_GLES2:
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_local);
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_usedepthtextures);
3334         Cvar_RegisterVariable(&r_viewfbo);
3335         Cvar_RegisterVariable(&r_rendertarget_debug);
3336         Cvar_RegisterVariable(&r_viewscale);
3337         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3338         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3339         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3340         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3341         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3342         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3343         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3344         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3345         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3346         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3347         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3348         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3349         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3350         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3351         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3352         Cvar_RegisterVariable(&r_glsl_postprocess);
3353         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3354         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3355         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3356         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3357         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3358         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3359         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3360         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3361         Cvar_RegisterVariable(&r_celshading);
3362         Cvar_RegisterVariable(&r_celoutlines);
3363         Cvar_RegisterVariable(&r_fxaa);
3364
3365         Cvar_RegisterVariable(&r_water);
3366         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3367         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3368         Cvar_RegisterVariable(&r_water_clippingplanebias);
3369         Cvar_RegisterVariable(&r_water_refractdistort);
3370         Cvar_RegisterVariable(&r_water_reflectdistort);
3371         Cvar_RegisterVariable(&r_water_scissormode);
3372         Cvar_RegisterVariable(&r_water_lowquality);
3373         Cvar_RegisterVariable(&r_water_hideplayer);
3374
3375         Cvar_RegisterVariable(&r_lerpsprites);
3376         Cvar_RegisterVariable(&r_lerpmodels);
3377         Cvar_RegisterVariable(&r_nolerp_list);
3378         Cvar_RegisterVariable(&r_lerplightstyles);
3379         Cvar_RegisterVariable(&r_waterscroll);
3380         Cvar_RegisterVariable(&r_bloom);
3381         Cvar_RegisterVariable(&r_colorfringe);
3382         Cvar_RegisterVariable(&r_bloom_colorscale);
3383         Cvar_RegisterVariable(&r_bloom_brighten);
3384         Cvar_RegisterVariable(&r_bloom_blur);
3385         Cvar_RegisterVariable(&r_bloom_resolution);
3386         Cvar_RegisterVariable(&r_bloom_colorexponent);
3387         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3388         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3389         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3390         Cvar_RegisterVariable(&r_hdr_glowintensity);
3391         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3392         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3393         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3394         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3395         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3396         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3397         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3398         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3399         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3400         Cvar_RegisterVariable(&developer_texturelogging);
3401         Cvar_RegisterVariable(&gl_lightmaps);
3402         Cvar_RegisterVariable(&r_test);
3403         Cvar_RegisterVariable(&r_batch_multidraw);
3404         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3405         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3406         Cvar_RegisterVariable(&r_glsl_skeletal);
3407         Cvar_RegisterVariable(&r_glsl_saturation);
3408         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3409         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3410         Cvar_RegisterVariable(&r_framedatasize);
3411         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3412                 Cvar_RegisterVariable(&r_buffermegs[i]);
3413         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3414         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3415         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3416         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3417         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3418                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3419 #ifdef DP_MOBILETOUCH
3420         // GLES devices have terrible depth precision in general, so...
3421         Cvar_SetValueQuick(&r_nearclip, 4);
3422         Cvar_SetValueQuick(&r_farclip_base, 4096);
3423         Cvar_SetValueQuick(&r_farclip_world, 0);
3424         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3425 #endif
3426         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3427 }
3428
3429 void Render_Init(void)
3430 {
3431         gl_backend_init();
3432         R_Textures_Init();
3433         GL_Main_Init();
3434         Font_Init();
3435         GL_Draw_Init();
3436         R_Shadow_Init();
3437         R_Sky_Init();
3438         GL_Surf_Init();
3439         Sbar_Init();
3440         R_Particles_Init();
3441         R_Explosion_Init();
3442         R_LightningBeams_Init();
3443         CL_MeshEntities_Init();
3444         Mod_RenderInit();
3445 }
3446
3447 static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits)
3448 {
3449         out[0] = ((signbits & 1) ? mins : maxs)[0];
3450         out[1] = ((signbits & 2) ? mins : maxs)[1];
3451         out[2] = ((signbits & 4) ? mins : maxs)[2];
3452 }
3453
3454 static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore)
3455 {
3456         int i;
3457         const mplane_t *p;
3458         vec3_t corner;
3459         if (r_trippy.integer)
3460                 return false;
3461         for (i = 0;i < numplanes;i++)
3462         {
3463                 if(i == ignore)
3464                         continue;
3465                 p = planes + i;
3466                 R_GetCornerOfBox(corner, mins, maxs, p->signbits);
3467                 if (DotProduct(p->normal, corner) < p->dist)
3468                         return true;
3469         }
3470         return false;
3471 }
3472
3473 qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs)
3474 {
3475         // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
3476         return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4);
3477 }
3478
3479 qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3480 {
3481         // nothing to ignore
3482         return _R_CullBox(mins, maxs, numplanes, planes, -1);
3483 }
3484
3485 //==================================================================================
3486
3487 // LadyHavoc: this stores temporary data used within the same frame
3488
3489 typedef struct r_framedata_mem_s
3490 {
3491         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3492         size_t size; // how much usable space
3493         size_t current; // how much space in use
3494         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3495         size_t wantedsize; // how much space was allocated
3496         unsigned char *data; // start of real data (16byte aligned)
3497 }
3498 r_framedata_mem_t;
3499
3500 static r_framedata_mem_t *r_framedata_mem;
3501
3502 void R_FrameData_Reset(void)
3503 {
3504         while (r_framedata_mem)
3505         {
3506                 r_framedata_mem_t *next = r_framedata_mem->purge;
3507                 Mem_Free(r_framedata_mem);
3508                 r_framedata_mem = next;
3509         }
3510 }
3511
3512 static void R_FrameData_Resize(qbool mustgrow)
3513 {
3514         size_t wantedsize;
3515         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3516         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3517         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3518         {
3519                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3520                 newmem->wantedsize = wantedsize;
3521                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3522                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3523                 newmem->current = 0;
3524                 newmem->mark = 0;
3525                 newmem->purge = r_framedata_mem;
3526                 r_framedata_mem = newmem;
3527         }
3528 }
3529
3530 void R_FrameData_NewFrame(void)
3531 {
3532         R_FrameData_Resize(false);
3533         if (!r_framedata_mem)
3534                 return;
3535         // if we ran out of space on the last frame, free the old memory now
3536         while (r_framedata_mem->purge)
3537         {
3538                 // repeatedly remove the second item in the list, leaving only head
3539                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3540                 Mem_Free(r_framedata_mem->purge);
3541                 r_framedata_mem->purge = next;
3542         }
3543         // reset the current mem pointer
3544         r_framedata_mem->current = 0;
3545         r_framedata_mem->mark = 0;
3546 }
3547
3548 void *R_FrameData_Alloc(size_t size)
3549 {
3550         void *data;
3551         float newvalue;
3552
3553         // align to 16 byte boundary - the data pointer is already aligned, so we
3554         // only need to ensure the size of every allocation is also aligned
3555         size = (size + 15) & ~15;
3556
3557         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3558         {
3559                 // emergency - we ran out of space, allocate more memory
3560                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3561                 newvalue = r_framedatasize.value * 2.0f;
3562                 // 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
3563                 if (sizeof(size_t) >= 8)
3564                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3565                 else
3566                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3567                 // this might not be a growing it, but we'll allocate another buffer every time
3568                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3569                 R_FrameData_Resize(true);
3570         }
3571
3572         data = r_framedata_mem->data + r_framedata_mem->current;
3573         r_framedata_mem->current += size;
3574
3575         // count the usage for stats
3576         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3577         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3578
3579         return (void *)data;
3580 }
3581
3582 void *R_FrameData_Store(size_t size, void *data)
3583 {
3584         void *d = R_FrameData_Alloc(size);
3585         if (d && data)
3586                 memcpy(d, data, size);
3587         return d;
3588 }
3589
3590 void R_FrameData_SetMark(void)
3591 {
3592         if (!r_framedata_mem)
3593                 return;
3594         r_framedata_mem->mark = r_framedata_mem->current;
3595 }
3596
3597 void R_FrameData_ReturnToMark(void)
3598 {
3599         if (!r_framedata_mem)
3600                 return;
3601         r_framedata_mem->current = r_framedata_mem->mark;
3602 }
3603
3604 //==================================================================================
3605
3606 // avoid reusing the same buffer objects on consecutive frames
3607 #define R_BUFFERDATA_CYCLE 3
3608
3609 typedef struct r_bufferdata_buffer_s
3610 {
3611         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3612         size_t size; // how much usable space
3613         size_t current; // how much space in use
3614         r_meshbuffer_t *buffer; // the buffer itself
3615 }
3616 r_bufferdata_buffer_t;
3617
3618 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3619 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3620
3621 /// frees all dynamic buffers
3622 void R_BufferData_Reset(void)
3623 {
3624         int cycle, type;
3625         r_bufferdata_buffer_t **p, *mem;
3626         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3627         {
3628                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3629                 {
3630                         // free all buffers
3631                         p = &r_bufferdata_buffer[cycle][type];
3632                         while (*p)
3633                         {
3634                                 mem = *p;
3635                                 *p = (*p)->purge;
3636                                 if (mem->buffer)
3637                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3638                                 Mem_Free(mem);
3639                         }
3640                 }
3641         }
3642 }
3643
3644 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3645 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3646 {
3647         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3648         size_t size;
3649         float newvalue = r_buffermegs[type].value;
3650
3651         // increase the cvar if we have to (but only if we already have a mem)
3652         if (mustgrow && mem)
3653                 newvalue *= 2.0f;
3654         newvalue = bound(0.25f, newvalue, 256.0f);
3655         while (newvalue * 1024*1024 < minsize)
3656                 newvalue *= 2.0f;
3657
3658         // clamp the cvar to valid range
3659         newvalue = bound(0.25f, newvalue, 256.0f);
3660         if (r_buffermegs[type].value != newvalue)
3661                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3662
3663         // calculate size in bytes
3664         size = (size_t)(newvalue * 1024*1024);
3665         size = bound(131072, size, 256*1024*1024);
3666
3667         // allocate a new buffer if the size is different (purge old one later)
3668         // or if we were told we must grow the buffer
3669         if (!mem || mem->size != size || mustgrow)
3670         {
3671                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3672                 mem->size = size;
3673                 mem->current = 0;
3674                 if (type == R_BUFFERDATA_VERTEX)
3675                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3676                 else if (type == R_BUFFERDATA_INDEX16)
3677                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3678                 else if (type == R_BUFFERDATA_INDEX32)
3679                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3680                 else if (type == R_BUFFERDATA_UNIFORM)
3681                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3682                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3683                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3684         }
3685 }
3686
3687 void R_BufferData_NewFrame(void)
3688 {
3689         int type;
3690         r_bufferdata_buffer_t **p, *mem;
3691         // cycle to the next frame's buffers
3692         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3693         // if we ran out of space on the last time we used these buffers, free the old memory now
3694         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3695         {
3696                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3697                 {
3698                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3699                         // free all but the head buffer, this is how we recycle obsolete
3700                         // buffers after they are no longer in use
3701                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3702                         while (*p)
3703                         {
3704                                 mem = *p;
3705                                 *p = (*p)->purge;
3706                                 if (mem->buffer)
3707                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3708                                 Mem_Free(mem);
3709                         }
3710                         // reset the current offset
3711                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3712                 }
3713         }
3714 }
3715
3716 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3717 {
3718         r_bufferdata_buffer_t *mem;
3719         int offset = 0;
3720         int padsize;
3721
3722         *returnbufferoffset = 0;
3723
3724         // align size to a byte boundary appropriate for the buffer type, this
3725         // makes all allocations have aligned start offsets
3726         if (type == R_BUFFERDATA_UNIFORM)
3727                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3728         else
3729                 padsize = (datasize + 15) & ~15;
3730
3731         // if we ran out of space in this buffer we must allocate a new one
3732         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)
3733                 R_BufferData_Resize(type, true, padsize);
3734
3735         // if the resize did not give us enough memory, fail
3736         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)
3737                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3738
3739         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3740         offset = (int)mem->current;
3741         mem->current += padsize;
3742
3743         // upload the data to the buffer at the chosen offset
3744         if (offset == 0)
3745                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3746         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3747
3748         // count the usage for stats
3749         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3750         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3751
3752         // return the buffer offset
3753         *returnbufferoffset = offset;
3754
3755         return mem->buffer;
3756 }
3757
3758 //==================================================================================
3759
3760 // LadyHavoc: animcache originally written by Echon, rewritten since then
3761
3762 /**
3763  * Animation cache prevents re-generating mesh data for an animated model
3764  * multiple times in one frame for lighting, shadowing, reflections, etc.
3765  */
3766
3767 void R_AnimCache_Free(void)
3768 {
3769 }
3770
3771 void R_AnimCache_ClearCache(void)
3772 {
3773         int i;
3774         entity_render_t *ent;
3775
3776         for (i = 0;i < r_refdef.scene.numentities;i++)
3777         {
3778                 ent = r_refdef.scene.entities[i];
3779                 ent->animcache_vertex3f = NULL;
3780                 ent->animcache_vertex3f_vertexbuffer = NULL;
3781                 ent->animcache_vertex3f_bufferoffset = 0;
3782                 ent->animcache_normal3f = NULL;
3783                 ent->animcache_normal3f_vertexbuffer = NULL;
3784                 ent->animcache_normal3f_bufferoffset = 0;
3785                 ent->animcache_svector3f = NULL;
3786                 ent->animcache_svector3f_vertexbuffer = NULL;
3787                 ent->animcache_svector3f_bufferoffset = 0;
3788                 ent->animcache_tvector3f = NULL;
3789                 ent->animcache_tvector3f_vertexbuffer = NULL;
3790                 ent->animcache_tvector3f_bufferoffset = 0;
3791                 ent->animcache_skeletaltransform3x4 = NULL;
3792                 ent->animcache_skeletaltransform3x4buffer = NULL;
3793                 ent->animcache_skeletaltransform3x4offset = 0;
3794                 ent->animcache_skeletaltransform3x4size = 0;
3795         }
3796 }
3797
3798 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3799 {
3800         model_t *model = ent->model;
3801         int numvertices;
3802
3803         // see if this ent is worth caching
3804         if (!model || !model->Draw || !model->AnimateVertices)
3805                 return false;
3806         // nothing to cache if it contains no animations and has no skeleton
3807         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3808                 return false;
3809         // see if it is already cached for gpuskeletal
3810         if (ent->animcache_skeletaltransform3x4)
3811                 return false;
3812         // see if it is already cached as a mesh
3813         if (ent->animcache_vertex3f)
3814         {
3815                 // check if we need to add normals or tangents
3816                 if (ent->animcache_normal3f)
3817                         wantnormals = false;
3818                 if (ent->animcache_svector3f)
3819                         wanttangents = false;
3820                 if (!wantnormals && !wanttangents)
3821                         return false;
3822         }
3823
3824         // check which kind of cache we need to generate
3825         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3826         {
3827                 // cache the skeleton so the vertex shader can use it
3828                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3829                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3830                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3831                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3832                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3833                 // note: this can fail if the buffer is at the grow limit
3834                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3835                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3836         }
3837         else if (ent->animcache_vertex3f)
3838         {
3839                 // mesh was already cached but we may need to add normals/tangents
3840                 // (this only happens with multiple views, reflections, cameras, etc)
3841                 if (wantnormals || wanttangents)
3842                 {
3843                         numvertices = model->surfmesh.num_vertices;
3844                         if (wantnormals)
3845                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3846                         if (wanttangents)
3847                         {
3848                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3849                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3850                         }
3851                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3852                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3853                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3854                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3855                 }
3856         }
3857         else
3858         {
3859                 // generate mesh cache
3860                 numvertices = model->surfmesh.num_vertices;
3861                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3862                 if (wantnormals)
3863                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3864                 if (wanttangents)
3865                 {
3866                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3867                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3868                 }
3869                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3870                 if (wantnormals || wanttangents)
3871                 {
3872                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3873                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3874                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3875                 }
3876                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3877                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3878                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3879         }
3880         return true;
3881 }
3882
3883 void R_AnimCache_CacheVisibleEntities(void)
3884 {
3885         int i;
3886
3887         // TODO: thread this
3888         // NOTE: R_PrepareRTLights() also caches entities
3889
3890         for (i = 0;i < r_refdef.scene.numentities;i++)
3891                 if (r_refdef.viewcache.entityvisible[i])
3892                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3893 }
3894
3895 //==================================================================================
3896
3897 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)
3898 {
3899         long unsigned int i;
3900         int j;
3901         vec3_t eyemins, eyemaxs;
3902         vec3_t boxmins, boxmaxs;
3903         vec3_t padmins, padmaxs;
3904         vec3_t start;
3905         vec3_t end;
3906         model_t *model = r_refdef.scene.worldmodel;
3907         static vec3_t positions[] = {
3908                 { 0.5f, 0.5f, 0.5f },
3909                 { 0.0f, 0.0f, 0.0f },
3910                 { 0.0f, 0.0f, 1.0f },
3911                 { 0.0f, 1.0f, 0.0f },
3912                 { 0.0f, 1.0f, 1.0f },
3913                 { 1.0f, 0.0f, 0.0f },
3914                 { 1.0f, 0.0f, 1.0f },
3915                 { 1.0f, 1.0f, 0.0f },
3916                 { 1.0f, 1.0f, 1.0f },
3917         };
3918
3919         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3920         if (numsamples < 0)
3921                 return true;
3922
3923         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3924         if (!r_refdef.view.usevieworiginculling)
3925                 return true;
3926
3927         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3928                 return true;
3929
3930         // expand the eye box a little
3931         eyemins[0] = eye[0] - eyejitter;
3932         eyemaxs[0] = eye[0] + eyejitter;
3933         eyemins[1] = eye[1] - eyejitter;
3934         eyemaxs[1] = eye[1] + eyejitter;
3935         eyemins[2] = eye[2] - eyejitter;
3936         eyemaxs[2] = eye[2] + eyejitter;
3937         // expand the box a little
3938         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3939         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3940         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3941         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3942         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3943         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3944         // make an even larger box for the acceptable area
3945         padmins[0] = boxmins[0] - pad;
3946         padmaxs[0] = boxmaxs[0] + pad;
3947         padmins[1] = boxmins[1] - pad;
3948         padmaxs[1] = boxmaxs[1] + pad;
3949         padmins[2] = boxmins[2] - pad;
3950         padmaxs[2] = boxmaxs[2] + pad;
3951
3952         // return true if eye overlaps enlarged box
3953         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3954                 return true;
3955
3956         VectorCopy(eye, start);
3957         // try specific positions in the box first - note that these can be cached
3958         if (r_cullentities_trace_entityocclusion.integer)
3959         {
3960                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3961                 {
3962                         trace_t trace;
3963                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3964                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3965                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3966                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3967                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3968                         // not picky - if the trace ended anywhere in the box we're good
3969                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3970                                 return true;
3971                 }
3972         }
3973         else
3974         {
3975                 // try center
3976                 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
3977                 if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3978                         return true;
3979         }
3980
3981         // try various random positions
3982         for (j = 0; j < numsamples; j++)
3983         {
3984                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3985                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3986                 if (r_cullentities_trace_entityocclusion.integer)
3987                 {
3988                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3989                         // not picky - if the trace ended anywhere in the box we're good
3990                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3991                                 return true;
3992                 }
3993                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3994                         return true;
3995         }
3996
3997         return false;
3998 }
3999
4000
4001 static void R_View_UpdateEntityVisible (void)
4002 {
4003         int i;
4004         int renderimask;
4005         int samples;
4006         entity_render_t *ent;
4007
4008         if (r_refdef.envmap || r_fb.water.hideplayer)
4009                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4010         else if (chase_active.integer || r_fb.water.renderingscene)
4011                 renderimask = RENDER_VIEWMODEL;
4012         else
4013                 renderimask = RENDER_EXTERIORMODEL;
4014         if (!r_drawviewmodel.integer)
4015                 renderimask |= RENDER_VIEWMODEL;
4016         if (!r_drawexteriormodel.integer)
4017                 renderimask |= RENDER_EXTERIORMODEL;
4018         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4019         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4020         {
4021                 // worldmodel can check visibility
4022                 for (i = 0;i < r_refdef.scene.numentities;i++)
4023                 {
4024                         ent = r_refdef.scene.entities[i];
4025                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4026                         {
4027                                 r_refdef.viewcache.entityvisible[i] = false;
4028                                 continue;
4029                         }
4030                         if (!(ent->flags & renderimask))
4031                         if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4032                         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))
4033                                 r_refdef.viewcache.entityvisible[i] = true;
4034                 }
4035         }
4036         else
4037         {
4038                 // no worldmodel or it can't check visibility
4039                 for (i = 0;i < r_refdef.scene.numentities;i++)
4040                 {
4041                         ent = r_refdef.scene.entities[i];
4042                         if (!(ent->flags & renderimask))
4043                         if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4044                                 r_refdef.viewcache.entityvisible[i] = true;
4045                 }
4046         }
4047         if (r_cullentities_trace.integer)
4048         {
4049                 for (i = 0;i < r_refdef.scene.numentities;i++)
4050                 {
4051                         if (!r_refdef.viewcache.entityvisible[i])
4052                                 continue;
4053                         ent = r_refdef.scene.entities[i];
4054                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4055                         {
4056                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4057                                 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))
4058                                         ent->last_trace_visibility = host.realtime;
4059                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4060                                         r_refdef.viewcache.entityvisible[i] = 0;
4061                         }
4062                 }
4063         }
4064 }
4065
4066 /// only used if skyrendermasked, and normally returns false
4067 static int R_DrawBrushModelsSky (void)
4068 {
4069         int i, sky;
4070         entity_render_t *ent;
4071
4072         sky = false;
4073         for (i = 0;i < r_refdef.scene.numentities;i++)
4074         {
4075                 if (!r_refdef.viewcache.entityvisible[i])
4076                         continue;
4077                 ent = r_refdef.scene.entities[i];
4078                 if (!ent->model || !ent->model->DrawSky)
4079                         continue;
4080                 ent->model->DrawSky(ent);
4081                 sky = true;
4082         }
4083         return sky;
4084 }
4085
4086 static void R_DrawNoModel(entity_render_t *ent);
4087 static void R_DrawModels(void)
4088 {
4089         int i;
4090         entity_render_t *ent;
4091
4092         for (i = 0;i < r_refdef.scene.numentities;i++)
4093         {
4094                 if (!r_refdef.viewcache.entityvisible[i])
4095                         continue;
4096                 ent = r_refdef.scene.entities[i];
4097                 r_refdef.stats[r_stat_entities]++;
4098
4099                 if (ent->model && ent->model->Draw != NULL)
4100                         ent->model->Draw(ent);
4101                 else
4102                         R_DrawNoModel(ent);
4103         }
4104 }
4105
4106 static void R_DrawModelsDepth(void)
4107 {
4108         int i;
4109         entity_render_t *ent;
4110
4111         for (i = 0;i < r_refdef.scene.numentities;i++)
4112         {
4113                 if (!r_refdef.viewcache.entityvisible[i])
4114                         continue;
4115                 ent = r_refdef.scene.entities[i];
4116                 if (ent->model && ent->model->DrawDepth != NULL)
4117                         ent->model->DrawDepth(ent);
4118         }
4119 }
4120
4121 static void R_DrawModelsDebug(void)
4122 {
4123         int i;
4124         entity_render_t *ent;
4125
4126         for (i = 0;i < r_refdef.scene.numentities;i++)
4127         {
4128                 if (!r_refdef.viewcache.entityvisible[i])
4129                         continue;
4130                 ent = r_refdef.scene.entities[i];
4131                 if (ent->model && ent->model->DrawDebug != NULL)
4132                         ent->model->DrawDebug(ent);
4133         }
4134 }
4135
4136 static void R_DrawModelsAddWaterPlanes(void)
4137 {
4138         int i;
4139         entity_render_t *ent;
4140
4141         for (i = 0;i < r_refdef.scene.numentities;i++)
4142         {
4143                 if (!r_refdef.viewcache.entityvisible[i])
4144                         continue;
4145                 ent = r_refdef.scene.entities[i];
4146                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4147                         ent->model->DrawAddWaterPlanes(ent);
4148         }
4149 }
4150
4151 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}};
4152
4153 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4154 {
4155         if (r_hdr_irisadaptation.integer)
4156         {
4157                 vec3_t p;
4158                 vec3_t ambient;
4159                 vec3_t diffuse;
4160                 vec3_t diffusenormal;
4161                 vec3_t forward;
4162                 vec_t brightness = 0.0f;
4163                 vec_t goal;
4164                 vec_t current;
4165                 vec_t d;
4166                 int c;
4167                 VectorCopy(r_refdef.view.forward, forward);
4168                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4169                 {
4170                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4171                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4172                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4173                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4174                         d = DotProduct(forward, diffusenormal);
4175                         brightness += VectorLength(ambient);
4176                         if (d > 0)
4177                                 brightness += d * VectorLength(diffuse);
4178                 }
4179                 brightness *= 1.0f / c;
4180                 brightness += 0.00001f; // make sure it's never zero
4181                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4182                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4183                 current = r_hdr_irisadaptation_value.value;
4184                 if (current < goal)
4185                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4186                 else if (current > goal)
4187                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4188                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4189                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4190         }
4191         else if (r_hdr_irisadaptation_value.value != 1.0f)
4192                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4193 }
4194
4195 extern cvar_t r_lockvisibility;
4196 extern cvar_t r_lockpvs;
4197
4198 static void R_View_SetFrustum(const int *scissor)
4199 {
4200         int i;
4201         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4202         vec3_t forward, left, up, origin, v;
4203         if(r_lockvisibility.integer)
4204                 return;
4205         if(scissor)
4206         {
4207                 // flipped x coordinates (because x points left here)
4208                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4209                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4210                 // non-flipped y coordinates
4211                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4212                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4213         }
4214
4215         // we can't trust r_refdef.view.forward and friends in reflected scenes
4216         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4217
4218 #if 0
4219         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4220         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4221         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4222         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4223         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4224         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4225         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4226         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4227         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4228         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4229         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4230         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4231 #endif
4232
4233 #if 0
4234         zNear = r_refdef.nearclip;
4235         nudge = 1.0 - 1.0 / (1<<23);
4236         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4237         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4238         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4239         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4240         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4241         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4242         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4243         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4244 #endif
4245
4246
4247
4248 #if 0
4249         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4250         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4251         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4252         r_refdef.view.frustum[0].dist = m[15] - m[12];
4253
4254         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4255         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4256         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4257         r_refdef.view.frustum[1].dist = m[15] + m[12];
4258
4259         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4260         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4261         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4262         r_refdef.view.frustum[2].dist = m[15] - m[13];
4263
4264         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4265         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4266         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4267         r_refdef.view.frustum[3].dist = m[15] + m[13];
4268
4269         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4270         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4271         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4272         r_refdef.view.frustum[4].dist = m[15] - m[14];
4273
4274         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4275         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4276         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4277         r_refdef.view.frustum[5].dist = m[15] + m[14];
4278 #endif
4279
4280         if (r_refdef.view.useperspective)
4281         {
4282                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4283                 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]);
4284                 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]);
4285                 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]);
4286                 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]);
4287
4288                 // then the normals from the corners relative to origin
4289                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4290                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4291                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4292                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4293
4294                 // in a NORMAL view, forward cross left == up
4295                 // in a REFLECTED view, forward cross left == down
4296                 // so our cross products above need to be adjusted for a left handed coordinate system
4297                 CrossProduct(forward, left, v);
4298                 if(DotProduct(v, up) < 0)
4299                 {
4300                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4301                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4302                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4303                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4304                 }
4305
4306                 // Leaving those out was a mistake, those were in the old code, and they
4307                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4308                 // I couldn't reproduce it after adding those normalizations. --blub
4309                 VectorNormalize(r_refdef.view.frustum[0].normal);
4310                 VectorNormalize(r_refdef.view.frustum[1].normal);
4311                 VectorNormalize(r_refdef.view.frustum[2].normal);
4312                 VectorNormalize(r_refdef.view.frustum[3].normal);
4313
4314                 // make the corners absolute
4315                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4316                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4317                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4318                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4319
4320                 // one more normal
4321                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4322
4323                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4324                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4325                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4326                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4327                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4328         }
4329         else
4330         {
4331                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4332                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4333                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4334                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4335                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4336                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4337                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4338                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4339                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4340                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4341         }
4342         r_refdef.view.numfrustumplanes = 5;
4343
4344         if (r_refdef.view.useclipplane)
4345         {
4346                 r_refdef.view.numfrustumplanes = 6;
4347                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4348         }
4349
4350         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4351                 PlaneClassify(r_refdef.view.frustum + i);
4352
4353         // LadyHavoc: note to all quake engine coders, Quake had a special case
4354         // for 90 degrees which assumed a square view (wrong), so I removed it,
4355         // Quake2 has it disabled as well.
4356
4357         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4358         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4359         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4360         //PlaneClassify(&frustum[0]);
4361
4362         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4363         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4364         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4365         //PlaneClassify(&frustum[1]);
4366
4367         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4368         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4369         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4370         //PlaneClassify(&frustum[2]);
4371
4372         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4373         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4374         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4375         //PlaneClassify(&frustum[3]);
4376
4377         // nearclip plane
4378         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4379         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4380         //PlaneClassify(&frustum[4]);
4381 }
4382
4383 static void R_View_Update(const int *myscissor)
4384 {
4385         R_Main_ResizeViewCache();
4386         R_View_SetFrustum(myscissor);
4387         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4388         R_View_UpdateEntityVisible();
4389 }
4390
4391 float viewscalefpsadjusted = 1.0f;
4392
4393 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4394 {
4395         const float *customclipplane = NULL;
4396         float plane[4];
4397         int viewy_adjusted;
4398         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4399         {
4400                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4401                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4402                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4403                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4404                         dist = r_refdef.view.clipplane.dist;
4405                 plane[0] = r_refdef.view.clipplane.normal[0];
4406                 plane[1] = r_refdef.view.clipplane.normal[1];
4407                 plane[2] = r_refdef.view.clipplane.normal[2];
4408                 plane[3] = -dist;
4409                 customclipplane = plane;
4410         }
4411
4412         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
4413         // Unless the render target is a FBO...
4414         viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy;
4415
4416         if (!r_refdef.view.useperspective)
4417                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4418         else if (vid.stencil && r_useinfinitefarclip.integer)
4419                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4420         else
4421                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4422         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4423         R_SetViewport(&r_refdef.view.viewport);
4424 }
4425
4426 void R_EntityMatrix(const matrix4x4_t *matrix)
4427 {
4428         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4429         {
4430                 gl_modelmatrixchanged = false;
4431                 gl_modelmatrix = *matrix;
4432                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4433                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4434                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4435                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4436                 CHECKGLERROR
4437                 switch(vid.renderpath)
4438                 {
4439                 case RENDERPATH_GL32:
4440                 case RENDERPATH_GLES2:
4441                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4442                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4443                         break;
4444                 }
4445         }
4446 }
4447
4448 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4449 {
4450         r_viewport_t viewport;
4451         int viewy_adjusted;
4452
4453         CHECKGLERROR
4454
4455         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
4456         // Unless the render target is a FBO...
4457         viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy;
4458
4459         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, viewy_adjusted, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4460         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4461         R_SetViewport(&viewport);
4462         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4463         GL_Color(1, 1, 1, 1);
4464         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4465         GL_BlendFunc(GL_ONE, GL_ZERO);
4466         GL_ScissorTest(false);
4467         GL_DepthMask(false);
4468         GL_DepthRange(0, 1);
4469         GL_DepthTest(false);
4470         GL_DepthFunc(GL_LEQUAL);
4471         R_EntityMatrix(&identitymatrix);
4472         R_Mesh_ResetTextureState();
4473         GL_PolygonOffset(0, 0);
4474         switch(vid.renderpath)
4475         {
4476         case RENDERPATH_GL32:
4477         case RENDERPATH_GLES2:
4478                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4479                 break;
4480         }
4481         GL_CullFace(GL_NONE);
4482
4483         CHECKGLERROR
4484 }
4485
4486 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4487 {
4488         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4489 }
4490
4491 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4492 {
4493         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4494         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4495         GL_Color(1, 1, 1, 1);
4496         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4497         GL_BlendFunc(GL_ONE, GL_ZERO);
4498         GL_ScissorTest(true);
4499         GL_DepthMask(true);
4500         GL_DepthRange(0, 1);
4501         GL_DepthTest(true);
4502         GL_DepthFunc(GL_LEQUAL);
4503         R_EntityMatrix(&identitymatrix);
4504         R_Mesh_ResetTextureState();
4505         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4506         switch(vid.renderpath)
4507         {
4508         case RENDERPATH_GL32:
4509         case RENDERPATH_GLES2:
4510                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4511                 break;
4512         }
4513         GL_CullFace(r_refdef.view.cullface_back);
4514 }
4515
4516 /*
4517 ================
4518 R_RenderView_UpdateViewVectors
4519 ================
4520 */
4521 void R_RenderView_UpdateViewVectors(void)
4522 {
4523         // break apart the view matrix into vectors for various purposes
4524         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4525         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4526         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4527         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4528         // make an inverted copy of the view matrix for tracking sprites
4529         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4530 }
4531
4532 void R_RenderTarget_FreeUnused(qbool force)
4533 {
4534         unsigned int i, j, end;
4535         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4536         for (i = 0; i < end; i++)
4537         {
4538                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4539                 // free resources for rendertargets that have not been used for a while
4540                 // (note: this check is run after the frame render, so any targets used
4541                 // this frame will not be affected even at low framerates)
4542                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4543                 {
4544                         if (r->fbo)
4545                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4546                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4547                                 if (r->colortexture[j])
4548                                         R_FreeTexture(r->colortexture[j]);
4549                         if (r->depthtexture)
4550                                 R_FreeTexture(r->depthtexture);
4551                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4552                 }
4553         }
4554 }
4555
4556 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4557 {
4558         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4559         x1 = x * iw;
4560         x2 = (x + w) * iw;
4561         y1 = (th - y) * ih;
4562         y2 = (th - y - h) * ih;
4563         texcoord2f[0] = x1;
4564         texcoord2f[2] = x2;
4565         texcoord2f[4] = x2;
4566         texcoord2f[6] = x1;
4567         texcoord2f[1] = y1;
4568         texcoord2f[3] = y1;
4569         texcoord2f[5] = y2;
4570         texcoord2f[7] = y2;
4571 }
4572
4573 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)
4574 {
4575         unsigned int i, j, end;
4576         r_rendertarget_t *r = NULL;
4577         char vabuf[256];
4578         // first try to reuse an existing slot if possible
4579         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4580         for (i = 0; i < end; i++)
4581         {
4582                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4583                 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)
4584                         break;
4585         }
4586         if (i == end)
4587         {
4588                 // no unused exact match found, so we have to make one in the first unused slot
4589                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4590                 r->texturewidth = texturewidth;
4591                 r->textureheight = textureheight;
4592                 r->colortextype[0] = colortextype0;
4593                 r->colortextype[1] = colortextype1;
4594                 r->colortextype[2] = colortextype2;
4595                 r->colortextype[3] = colortextype3;
4596                 r->depthtextype = depthtextype;
4597                 r->depthisrenderbuffer = depthisrenderbuffer;
4598                 for (j = 0; j < 4; j++)
4599                         if (r->colortextype[j])
4600                                 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);
4601                 if (r->depthtextype)
4602                 {
4603                         if (r->depthisrenderbuffer)
4604                                 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);
4605                         else
4606                                 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);
4607                 }
4608                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4609         }
4610         r_refdef.stats[r_stat_rendertargets_used]++;
4611         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4612         r->lastusetime = host.realtime;
4613         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4614         return r;
4615 }
4616
4617 static void R_Water_StartFrame(int viewwidth, int viewheight)
4618 {
4619         int waterwidth, waterheight;
4620
4621         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4622                 return;
4623
4624         // set waterwidth and waterheight to the water resolution that will be
4625         // used (often less than the screen resolution for faster rendering)
4626         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4627         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4628
4629         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4630                 waterwidth = waterheight = 0;
4631
4632         // set up variables that will be used in shader setup
4633         r_fb.water.waterwidth = waterwidth;
4634         r_fb.water.waterheight = waterheight;
4635         r_fb.water.texturewidth = waterwidth;
4636         r_fb.water.textureheight = waterheight;
4637         r_fb.water.camerawidth = waterwidth;
4638         r_fb.water.cameraheight = waterheight;
4639         r_fb.water.screenscale[0] = 0.5f;
4640         r_fb.water.screenscale[1] = 0.5f;
4641         r_fb.water.screencenter[0] = 0.5f;
4642         r_fb.water.screencenter[1] = 0.5f;
4643         r_fb.water.enabled = waterwidth != 0;
4644
4645         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4646         r_fb.water.numwaterplanes = 0;
4647 }
4648
4649 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4650 {
4651         int planeindex, bestplaneindex, vertexindex;
4652         vec3_t mins, maxs, normal, center, v, n;
4653         vec_t planescore, bestplanescore;
4654         mplane_t plane;
4655         r_waterstate_waterplane_t *p;
4656         texture_t *t = R_GetCurrentTexture(surface->texture);
4657
4658         rsurface.texture = t;
4659         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4660         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4661         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4662                 return;
4663         // average the vertex normals, find the surface bounds (after deformvertexes)
4664         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4665         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4666         VectorCopy(n, normal);
4667         VectorCopy(v, mins);
4668         VectorCopy(v, maxs);
4669         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4670         {
4671                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4672                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4673                 VectorAdd(normal, n, normal);
4674                 mins[0] = min(mins[0], v[0]);
4675                 mins[1] = min(mins[1], v[1]);
4676                 mins[2] = min(mins[2], v[2]);
4677                 maxs[0] = max(maxs[0], v[0]);
4678                 maxs[1] = max(maxs[1], v[1]);
4679                 maxs[2] = max(maxs[2], v[2]);
4680         }
4681         VectorNormalize(normal);
4682         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4683
4684         VectorCopy(normal, plane.normal);
4685         VectorNormalize(plane.normal);
4686         plane.dist = DotProduct(center, plane.normal);
4687         PlaneClassify(&plane);
4688         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4689         {
4690                 // skip backfaces (except if nocullface is set)
4691 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4692 //                      return;
4693                 VectorNegate(plane.normal, plane.normal);
4694                 plane.dist *= -1;
4695                 PlaneClassify(&plane);
4696         }
4697
4698
4699         // find a matching plane if there is one
4700         bestplaneindex = -1;
4701         bestplanescore = 1048576.0f;
4702         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4703         {
4704                 if(p->camera_entity == t->camera_entity)
4705                 {
4706                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4707                         if (bestplaneindex < 0 || bestplanescore > planescore)
4708                         {
4709                                 bestplaneindex = planeindex;
4710                                 bestplanescore = planescore;
4711                         }
4712                 }
4713         }
4714         planeindex = bestplaneindex;
4715
4716         // if this surface does not fit any known plane rendered this frame, add one
4717         if (planeindex < 0 || bestplanescore > 0.001f)
4718         {
4719                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4720                 {
4721                         // store the new plane
4722                         planeindex = r_fb.water.numwaterplanes++;
4723                         p = r_fb.water.waterplanes + planeindex;
4724                         p->plane = plane;
4725                         // clear materialflags and pvs
4726                         p->materialflags = 0;
4727                         p->pvsvalid = false;
4728                         p->camera_entity = t->camera_entity;
4729                         VectorCopy(mins, p->mins);
4730                         VectorCopy(maxs, p->maxs);
4731                 }
4732                 else
4733                 {
4734                         // We're totally screwed.
4735                         return;
4736                 }
4737         }
4738         else
4739         {
4740                 // merge mins/maxs when we're adding this surface to the plane
4741                 p = r_fb.water.waterplanes + planeindex;
4742                 p->mins[0] = min(p->mins[0], mins[0]);
4743                 p->mins[1] = min(p->mins[1], mins[1]);
4744                 p->mins[2] = min(p->mins[2], mins[2]);
4745                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4746                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4747                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4748         }
4749         // merge this surface's materialflags into the waterplane
4750         p->materialflags |= t->currentmaterialflags;
4751         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4752         {
4753                 // merge this surface's PVS into the waterplane
4754                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4755                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4756                 {
4757                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4758                         p->pvsvalid = true;
4759                 }
4760         }
4761 }
4762
4763 extern cvar_t r_drawparticles;
4764 extern cvar_t r_drawdecals;
4765
4766 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4767 {
4768         int myscissor[4];
4769         r_refdef_view_t originalview;
4770         r_refdef_view_t myview;
4771         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;
4772         r_waterstate_waterplane_t *p;
4773         vec3_t visorigin;
4774         r_rendertarget_t *rt;
4775
4776         originalview = r_refdef.view;
4777
4778         // lowquality hack, temporarily shut down some cvars and restore afterwards
4779         qualityreduction = r_water_lowquality.integer;
4780         if (qualityreduction > 0)
4781         {
4782                 if (qualityreduction >= 1)
4783                 {
4784                         old_r_shadows = r_shadows.integer;
4785                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4786                         old_r_dlight = r_shadow_realtime_dlight.integer;
4787                         Cvar_SetValueQuick(&r_shadows, 0);
4788                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4789                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4790                 }
4791                 if (qualityreduction >= 2)
4792                 {
4793                         old_r_dynamic = r_dynamic.integer;
4794                         old_r_particles = r_drawparticles.integer;
4795                         old_r_decals = r_drawdecals.integer;
4796                         Cvar_SetValueQuick(&r_dynamic, 0);
4797                         Cvar_SetValueQuick(&r_drawparticles, 0);
4798                         Cvar_SetValueQuick(&r_drawdecals, 0);
4799                 }
4800         }
4801
4802         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4803         {
4804                 p->rt_reflection = NULL;
4805                 p->rt_refraction = NULL;
4806                 p->rt_camera = NULL;
4807         }
4808
4809         // render views
4810         r_refdef.view = originalview;
4811         r_refdef.view.showdebug = false;
4812         r_refdef.view.width = r_fb.water.waterwidth;
4813         r_refdef.view.height = r_fb.water.waterheight;
4814         r_refdef.view.useclipplane = true;
4815         myview = r_refdef.view;
4816         r_fb.water.renderingscene = true;
4817         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4818         {
4819                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4820                         continue;
4821
4822                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4823                 {
4824                         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);
4825                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4826                                 goto error;
4827                         r_refdef.view = myview;
4828                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4829                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4830                         if(r_water_scissormode.integer)
4831                         {
4832                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4833                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4834                                 {
4835                                         p->rt_reflection = NULL;
4836                                         p->rt_refraction = NULL;
4837                                         p->rt_camera = NULL;
4838                                         continue;
4839                                 }
4840                         }
4841
4842                         r_refdef.view.clipplane = p->plane;
4843                         // reflected view origin may be in solid, so don't cull with it
4844                         r_refdef.view.usevieworiginculling = false;
4845                         // reverse the cullface settings for this render
4846                         r_refdef.view.cullface_front = GL_FRONT;
4847                         r_refdef.view.cullface_back = GL_BACK;
4848                         // combined pvs (based on what can be seen from each surface center)
4849                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4850                         {
4851                                 r_refdef.view.usecustompvs = true;
4852                                 if (p->pvsvalid)
4853                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4854                                 else
4855                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4856                         }
4857
4858                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4859                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4860                         GL_ScissorTest(false);
4861                         R_ClearScreen(r_refdef.fogenabled);
4862                         GL_ScissorTest(true);
4863                         R_View_Update(r_water_scissormode.integer & 2 ? myscissor : NULL);
4864                         R_AnimCache_CacheVisibleEntities();
4865                         if(r_water_scissormode.integer & 1)
4866                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4867                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4868
4869                         r_fb.water.hideplayer = false;
4870                         p->rt_reflection = rt;
4871                 }
4872
4873                 // render the normal view scene and copy into texture
4874                 // (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)
4875                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4876                 {
4877                         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);
4878                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4879                                 goto error;
4880                         r_refdef.view = myview;
4881                         if(r_water_scissormode.integer)
4882                         {
4883                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4884                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4885                                 {
4886                                         p->rt_reflection = NULL;
4887                                         p->rt_refraction = NULL;
4888                                         p->rt_camera = NULL;
4889                                         continue;
4890                                 }
4891                         }
4892
4893                         // combined pvs (based on what can be seen from each surface center)
4894                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4895                         {
4896                                 r_refdef.view.usecustompvs = true;
4897                                 if (p->pvsvalid)
4898                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4899                                 else
4900                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4901                         }
4902
4903                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4904
4905                         r_refdef.view.clipplane = p->plane;
4906                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4907                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4908
4909                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4910                         {
4911                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4912                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4913                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4914                                 R_RenderView_UpdateViewVectors();
4915                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4916                                 {
4917                                         r_refdef.view.usecustompvs = true;
4918                                         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);
4919                                 }
4920                         }
4921
4922                         PlaneClassify(&r_refdef.view.clipplane);
4923
4924                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4925                         GL_ScissorTest(false);
4926                         R_ClearScreen(r_refdef.fogenabled);
4927                         GL_ScissorTest(true);
4928                         R_View_Update(r_water_scissormode.integer & 2 ? myscissor : NULL);
4929                         R_AnimCache_CacheVisibleEntities();
4930                         if(r_water_scissormode.integer & 1)
4931                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4932                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4933
4934                         r_fb.water.hideplayer = false;
4935                         p->rt_refraction = rt;
4936                 }
4937                 else if (p->materialflags & MATERIALFLAG_CAMERA)
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
4944                         r_refdef.view.clipplane = p->plane;
4945                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4946                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4947
4948                         r_refdef.view.width = r_fb.water.camerawidth;
4949                         r_refdef.view.height = r_fb.water.cameraheight;
4950                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4951                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4952                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4953                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4954
4955                         if(p->camera_entity)
4956                         {
4957                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4958                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4959                         }
4960
4961                         // note: all of the view is used for displaying... so
4962                         // there is no use in scissoring
4963
4964                         // reverse the cullface settings for this render
4965                         r_refdef.view.cullface_front = GL_FRONT;
4966                         r_refdef.view.cullface_back = GL_BACK;
4967                         // also reverse the view matrix
4968                         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
4969                         R_RenderView_UpdateViewVectors();
4970                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4971                         {
4972                                 r_refdef.view.usecustompvs = true;
4973                                 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);
4974                         }
4975
4976                         // camera needs no clipplane
4977                         r_refdef.view.useclipplane = false;
4978                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4979                         r_refdef.view.usevieworiginculling = false;
4980
4981                         PlaneClassify(&r_refdef.view.clipplane);
4982
4983                         r_fb.water.hideplayer = false;
4984
4985                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4986                         GL_ScissorTest(false);
4987                         R_ClearScreen(r_refdef.fogenabled);
4988                         GL_ScissorTest(true);
4989                         R_View_Update(NULL);
4990                         R_AnimCache_CacheVisibleEntities();
4991                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4992
4993                         r_fb.water.hideplayer = false;
4994                         p->rt_camera = rt;
4995                 }
4996
4997         }
4998         r_fb.water.renderingscene = false;
4999         r_refdef.view = originalview;
5000         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5001         R_View_Update(NULL);
5002         R_AnimCache_CacheVisibleEntities();
5003         goto finish;
5004 error:
5005         r_refdef.view = originalview;
5006         r_fb.water.renderingscene = false;
5007         Cvar_SetValueQuick(&r_water, 0);
5008         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5009 finish:
5010         // lowquality hack, restore cvars
5011         if (qualityreduction > 0)
5012         {
5013                 if (qualityreduction >= 1)
5014                 {
5015                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5016                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5017                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5018                 }
5019                 if (qualityreduction >= 2)
5020                 {
5021                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5022                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5023                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5024                 }
5025         }
5026 }
5027
5028 static void R_Bloom_StartFrame(void)
5029 {
5030         int screentexturewidth, screentextureheight;
5031         textype_t textype = TEXTYPE_COLORBUFFER;
5032         double scale;
5033
5034         // clear the pointers to rendertargets from last frame as they're stale
5035         r_fb.rt_screen = NULL;
5036         r_fb.rt_bloom = NULL;
5037
5038         switch (vid.renderpath)
5039         {
5040         case RENDERPATH_GL32:
5041                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5042                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5043                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5044                 break;
5045         case RENDERPATH_GLES2:
5046                 r_fb.usedepthtextures = false;
5047                 break;
5048         }
5049
5050         if (r_viewscale_fpsscaling.integer)
5051         {
5052                 double actualframetime;
5053                 double targetframetime;
5054                 double adjust;
5055                 actualframetime = r_refdef.lastdrawscreentime;
5056                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5057                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5058                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5059                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5060                 {
5061                         if (adjust > 0)
5062                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5063                         else
5064                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5065                 }
5066                 viewscalefpsadjusted += adjust;
5067                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5068         }
5069         else
5070                 viewscalefpsadjusted = 1.0f;
5071
5072         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5073         if (vid.mode.samples)
5074                 scale *= sqrt(vid.mode.samples); // supersampling
5075         scale = bound(0.03125f, scale, 4.0f);
5076         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5077         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5078         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5079         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5080
5081         // set bloomwidth and bloomheight to the bloom resolution that will be
5082         // used (often less than the screen resolution for faster rendering)
5083         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5084         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5085         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5086         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5087         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5088
5089         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))
5090         {
5091                 Cvar_SetValueQuick(&r_bloom, 0);
5092                 Cvar_SetValueQuick(&r_motionblur, 0);
5093                 Cvar_SetValueQuick(&r_damageblur, 0);
5094         }
5095         if (!r_bloom.integer)
5096                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5097
5098         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5099         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5100         {
5101                 if (r_fb.ghosttexture)
5102                         R_FreeTexture(r_fb.ghosttexture);
5103                 r_fb.ghosttexture = NULL;
5104
5105                 r_fb.screentexturewidth = screentexturewidth;
5106                 r_fb.screentextureheight = screentextureheight;
5107                 r_fb.textype = textype;
5108
5109                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5110                 {
5111                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5112                                 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);
5113                         r_fb.ghosttexture_valid = false;
5114                 }
5115         }
5116
5117         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5118
5119         r_refdef.view.clear = true;
5120 }
5121
5122 static void R_Bloom_MakeTexture(void)
5123 {
5124         int x, range, dir;
5125         float xoffset, yoffset, r, brighten;
5126         float colorscale = r_bloom_colorscale.value;
5127         r_viewport_t bloomviewport;
5128         r_rendertarget_t *prev, *cur;
5129         textype_t textype = r_fb.rt_screen->colortextype[0];
5130
5131         r_refdef.stats[r_stat_bloom]++;
5132
5133         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5134
5135         // scale down screen texture to the bloom texture size
5136         CHECKGLERROR
5137         prev = r_fb.rt_screen;
5138         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5139         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5140         R_SetViewport(&bloomviewport);
5141         GL_CullFace(GL_NONE);
5142         GL_DepthTest(false);
5143         GL_BlendFunc(GL_ONE, GL_ZERO);
5144         GL_Color(colorscale, colorscale, colorscale, 1);
5145         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5146         // TODO: do boxfilter scale-down in shader?
5147         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5148         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5149         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5150         // we now have a properly scaled bloom image
5151
5152         // multiply bloom image by itself as many times as desired to darken it
5153         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5154         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5155         {
5156                 prev = cur;
5157                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5158                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5159                 x *= 2;
5160                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5161                 if(x <= 2)
5162                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5163                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5164                 GL_Color(1,1,1,1); // no fix factor supported here
5165                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5166                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5167                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5168                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5169         }
5170         CHECKGLERROR
5171
5172         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5173         brighten = r_bloom_brighten.value;
5174         brighten = sqrt(brighten);
5175         if(range >= 1)
5176                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5177
5178         for (dir = 0;dir < 2;dir++)
5179         {
5180                 prev = cur;
5181                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5182                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5183                 // blend on at multiple vertical offsets to achieve a vertical blur
5184                 // TODO: do offset blends using GLSL
5185                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5186                 CHECKGLERROR
5187                 GL_BlendFunc(GL_ONE, GL_ZERO);
5188                 CHECKGLERROR
5189                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5190                 CHECKGLERROR
5191                 for (x = -range;x <= range;x++)
5192                 {
5193                         if (!dir){xoffset = 0;yoffset = x;}
5194                         else {xoffset = x;yoffset = 0;}
5195                         xoffset /= (float)prev->texturewidth;
5196                         yoffset /= (float)prev->textureheight;
5197                         // compute a texcoord array with the specified x and y offset
5198                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5199                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5200                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5201                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5202                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5203                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5204                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5205                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5206                         // this r value looks like a 'dot' particle, fading sharply to
5207                         // black at the edges
5208                         // (probably not realistic but looks good enough)
5209                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5210                         //r = brighten/(range*2+1);
5211                         r = brighten / (range * 2 + 1);
5212                         if(range >= 1)
5213                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5214                         if (r <= 0)
5215                                 continue;
5216                         CHECKGLERROR
5217                         GL_Color(r, r, r, 1);
5218                         CHECKGLERROR
5219                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5220                         CHECKGLERROR
5221                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5222                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5223                         CHECKGLERROR
5224                         GL_BlendFunc(GL_ONE, GL_ONE);
5225                         CHECKGLERROR
5226                 }
5227         }
5228
5229         // now we have the bloom image, so keep track of it
5230         r_fb.rt_bloom = cur;
5231 }
5232
5233 static qbool R_BlendView_IsTrivial(int viewwidth, int viewheight, int width, int height)
5234 {
5235         // Scaling requested?
5236         if (viewwidth != width || viewheight != height)
5237                 return false;
5238         // Higher bit depth or explicit FBO requested?
5239         if (r_viewfbo.integer)
5240                 return false;
5241         // Non-trivial postprocessing shader permutation?
5242         if (r_fb.bloomwidth
5243         || r_refdef.viewblend[3] > 0
5244         || !vid_gammatables_trivial
5245         || r_glsl_postprocess.integer
5246         || ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1)))
5247                 return false;
5248         // Other reasons for a non-trivial default postprocessing shader?
5249         // (See R_CompileShader_CheckStaticParms but only those relevant for MODE_POSTPROCESS in shader_glsl.h)
5250         // Skip: if (r_glsl_saturation_redcompensate.integer) (already covered by saturation above).
5251         // Skip: if (r_glsl_postprocess.integer) (already covered by r_glsl_postprocess above).
5252         // Skip: if (r_glsl_postprocess_uservec1_enable.integer) (already covered by r_glsl_postprocessing above).
5253         if (r_fxaa.integer)
5254                 return false;
5255         if (r_colorfringe.value)
5256                 return false;
5257         return true;
5258 }
5259
5260 static void R_MotionBlurView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5261 {
5262         R_EntityMatrix(&identitymatrix);
5263
5264         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || (r_damageblur.value > 0 && cl.cshifts[CSHIFT_DAMAGE].percent != 0)) && r_fb.ghosttexture)
5265         {
5266                 // declare variables
5267                 float blur_factor, blur_mouseaccel, blur_velocity;
5268                 static float blur_average;
5269                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5270
5271                 // set a goal for the factoring
5272                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5273                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5274                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5275                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5276                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5277                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5278
5279                 // from the goal, pick an averaged value between goal and last value
5280                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5281                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5282
5283                 // enforce minimum amount of blur
5284                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5285
5286                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5287
5288                 // calculate values into a standard alpha
5289                 cl.motionbluralpha = 1 - exp(-
5290                                 (
5291                                         (r_motionblur.value * blur_factor / 80)
5292                                         +
5293                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5294                                 )
5295                                 /
5296                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5297                                 );
5298
5299                 // randomization for the blur value to combat persistent ghosting
5300                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5301                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5302
5303                 // apply the blur on top of the current view
5304                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5305                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5306                 {
5307                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5308                         GL_Color(1, 1, 1, cl.motionbluralpha);
5309                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5310                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5311                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5312                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5313                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5314                 }
5315
5316                 // updates old view angles for next pass
5317                 VectorCopy(cl.viewangles, blur_oldangles);
5318
5319                 // copy view into the ghost texture
5320                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5321                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5322                 r_fb.ghosttexture_valid = true;
5323         }
5324 }
5325
5326 static void R_BlendView(rtexture_t *viewcolortexture, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5327 {
5328         uint64_t permutation;
5329         float uservecs[4][4];
5330         rtexture_t *viewtexture;
5331         rtexture_t *bloomtexture;
5332
5333         R_EntityMatrix(&identitymatrix);
5334
5335         if (r_fb.bloomwidth)
5336         {
5337                 // make the bloom texture
5338                 R_Bloom_MakeTexture();
5339         }
5340
5341 #if _MSC_VER >= 1400
5342 #define sscanf sscanf_s
5343 #endif
5344         memset(uservecs, 0, sizeof(uservecs));
5345         if (r_glsl_postprocess_uservec1_enable.integer)
5346                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5347         if (r_glsl_postprocess_uservec2_enable.integer)
5348                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5349         if (r_glsl_postprocess_uservec3_enable.integer)
5350                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5351         if (r_glsl_postprocess_uservec4_enable.integer)
5352                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5353
5354         // render to the screen fbo
5355         R_ResetViewRendering2D(fbo, depthtexture, colortexture, x, y, width, height);
5356         GL_Color(1, 1, 1, 1);
5357         GL_BlendFunc(GL_ONE, GL_ZERO);
5358
5359         viewtexture = viewcolortexture;
5360         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5361
5362         if (r_rendertarget_debug.integer >= 0)
5363         {
5364                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5365                 if (rt && rt->colortexture[0])
5366                 {
5367                         viewtexture = rt->colortexture[0];
5368                         bloomtexture = NULL;
5369                 }
5370         }
5371
5372         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5373         switch(vid.renderpath)
5374         {
5375         case RENDERPATH_GL32:
5376         case RENDERPATH_GLES2:
5377                 permutation =
5378                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5379                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5380                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5381                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5382                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5383                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5384                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5385                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5386                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5387                 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]);
5388                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5389                 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]);
5390                 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]);
5391                 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]);
5392                 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]);
5393                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5394                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5395                 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);
5396                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5397                 break;
5398         }
5399         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5400         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5401 }
5402
5403 matrix4x4_t r_waterscrollmatrix;
5404
5405 void R_UpdateFog(void)
5406 {
5407         // Nehahra fog
5408         if (gamemode == GAME_NEHAHRA)
5409         {
5410                 if (gl_fogenable.integer)
5411                 {
5412                         r_refdef.oldgl_fogenable = true;
5413                         r_refdef.fog_density = gl_fogdensity.value;
5414                         r_refdef.fog_red = gl_fogred.value;
5415                         r_refdef.fog_green = gl_foggreen.value;
5416                         r_refdef.fog_blue = gl_fogblue.value;
5417                         r_refdef.fog_alpha = 1;
5418                         r_refdef.fog_start = 0;
5419                         r_refdef.fog_end = gl_skyclip.value;
5420                         r_refdef.fog_height = 1<<30;
5421                         r_refdef.fog_fadedepth = 128;
5422                 }
5423                 else if (r_refdef.oldgl_fogenable)
5424                 {
5425                         r_refdef.oldgl_fogenable = false;
5426                         r_refdef.fog_density = 0;
5427                         r_refdef.fog_red = 0;
5428                         r_refdef.fog_green = 0;
5429                         r_refdef.fog_blue = 0;
5430                         r_refdef.fog_alpha = 0;
5431                         r_refdef.fog_start = 0;
5432                         r_refdef.fog_end = 0;
5433                         r_refdef.fog_height = 1<<30;
5434                         r_refdef.fog_fadedepth = 128;
5435                 }
5436         }
5437
5438         // fog parms
5439         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5440         r_refdef.fog_start = max(0, r_refdef.fog_start);
5441         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5442
5443         if (r_refdef.fog_density && r_drawfog.integer)
5444         {
5445                 r_refdef.fogenabled = true;
5446                 // this is the point where the fog reaches 0.9986 alpha, which we
5447                 // consider a good enough cutoff point for the texture
5448                 // (0.9986 * 256 == 255.6)
5449                 if (r_fog_exp2.integer)
5450                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5451                 else
5452                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5453                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5454                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5455                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5456                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5457                         R_BuildFogHeightTexture();
5458                 // fog color was already set
5459                 // update the fog texture
5460                 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)
5461                         R_BuildFogTexture();
5462                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5463                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5464         }
5465         else
5466                 r_refdef.fogenabled = false;
5467
5468         // fog color
5469         if (r_refdef.fog_density)
5470         {
5471                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5472                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5473                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5474
5475                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5476                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5477                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5478                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5479
5480                 {
5481                         vec3_t fogvec;
5482                         VectorCopy(r_refdef.fogcolor, fogvec);
5483                         //   color.rgb *= ContrastBoost * SceneBrightness;
5484                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5485                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5486                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5487                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5488                 }
5489         }
5490 }
5491
5492 void R_UpdateVariables(void)
5493 {
5494         R_Textures_Frame();
5495
5496         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5497
5498         r_refdef.farclip = r_farclip_base.value;
5499         if (r_refdef.scene.worldmodel)
5500                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5501         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5502
5503         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5504                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5505         r_refdef.polygonfactor = 0;
5506         r_refdef.polygonoffset = 0;
5507
5508         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5509         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5510         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5511         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5512         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5513         if (r_refdef.scene.worldmodel)
5514         {
5515                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5516
5517                 // Apply the default lightstyle to the lightmap even on q3bsp
5518                 if (cl.worldmodel && cl.worldmodel->type == mod_brushq3) {
5519                         r_refdef.scene.lightmapintensity *= r_refdef.scene.rtlightstylevalue[0];
5520                 }
5521         }
5522         if (r_showsurfaces.integer)
5523         {
5524                 r_refdef.scene.rtworld = false;
5525                 r_refdef.scene.rtworldshadows = false;
5526                 r_refdef.scene.rtdlight = false;
5527                 r_refdef.scene.rtdlightshadows = false;
5528                 r_refdef.scene.lightmapintensity = 0;
5529         }
5530
5531         r_gpuskeletal = false;
5532         switch(vid.renderpath)
5533         {
5534         case RENDERPATH_GL32:
5535                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5536         case RENDERPATH_GLES2:
5537                 if(!vid_gammatables_trivial)
5538                 {
5539                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5540                         {
5541                                 // build GLSL gamma texture
5542 #define RAMPWIDTH 256
5543                                 unsigned short ramp[RAMPWIDTH * 3];
5544                                 unsigned char rampbgr[RAMPWIDTH][4];
5545                                 int i;
5546
5547                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5548
5549                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5550                                 for(i = 0; i < RAMPWIDTH; ++i)
5551                                 {
5552                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5553                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5554                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5555                                         rampbgr[i][3] = 0;
5556                                 }
5557                                 if (r_texture_gammaramps)
5558                                 {
5559                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5560                                 }
5561                                 else
5562                                 {
5563                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5564                                 }
5565                         }
5566                 }
5567                 else
5568                 {
5569                         // remove GLSL gamma texture
5570                 }
5571                 break;
5572         }
5573 }
5574
5575 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5576 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5577 /*
5578 ================
5579 R_SelectScene
5580 ================
5581 */
5582 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5583         if( scenetype != r_currentscenetype ) {
5584                 // store the old scenetype
5585                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5586                 r_currentscenetype = scenetype;
5587                 // move in the new scene
5588                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5589         }
5590 }
5591
5592 /*
5593 ================
5594 R_GetScenePointer
5595 ================
5596 */
5597 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5598 {
5599         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5600         if( scenetype == r_currentscenetype ) {
5601                 return &r_refdef.scene;
5602         } else {
5603                 return &r_scenes_store[ scenetype ];
5604         }
5605 }
5606
5607 static int R_SortEntities_Compare(const void *ap, const void *bp)
5608 {
5609         const entity_render_t *a = *(const entity_render_t **)ap;
5610         const entity_render_t *b = *(const entity_render_t **)bp;
5611
5612         // 1. compare model
5613         if(a->model < b->model)
5614                 return -1;
5615         if(a->model > b->model)
5616                 return +1;
5617
5618         // 2. compare skin
5619         // TODO possibly calculate the REAL skinnum here first using
5620         // skinscenes?
5621         if(a->skinnum < b->skinnum)
5622                 return -1;
5623         if(a->skinnum > b->skinnum)
5624                 return +1;
5625
5626         // everything we compared is equal
5627         return 0;
5628 }
5629 static void R_SortEntities(void)
5630 {
5631         // below or equal 2 ents, sorting never gains anything
5632         if(r_refdef.scene.numentities <= 2)
5633                 return;
5634         // sort
5635         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5636 }
5637
5638 /*
5639 ================
5640 R_RenderView
5641 ================
5642 */
5643 extern cvar_t r_shadow_bouncegrid;
5644 extern cvar_t v_isometric;
5645 extern void V_MakeViewIsometric(void);
5646 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5647 {
5648         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5649         int viewfbo = 0;
5650         rtexture_t *viewdepthtexture = NULL;
5651         rtexture_t *viewcolortexture = NULL;
5652         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5653         qbool skipblend;
5654
5655         // finish any 2D rendering that was queued
5656         DrawQ_Finish();
5657
5658         if (r_timereport_active)
5659                 R_TimeReport("start");
5660         r_textureframe++; // used only by R_GetCurrentTexture
5661         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5662
5663         if(R_CompileShader_CheckStaticParms())
5664                 R_GLSL_Restart_f(cmd_local);
5665
5666         if (!r_drawentities.integer)
5667                 r_refdef.scene.numentities = 0;
5668         else if (r_sortentities.integer)
5669                 R_SortEntities();
5670
5671         R_AnimCache_ClearCache();
5672
5673         /* adjust for stereo display */
5674         if(R_Stereo_Active())
5675         {
5676                 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);
5677                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5678         }
5679
5680         if (r_refdef.view.isoverlay)
5681         {
5682                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5683                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5684                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5685                 R_TimeReport("depthclear");
5686
5687                 r_refdef.view.showdebug = false;
5688
5689                 r_fb.water.enabled = false;
5690                 r_fb.water.numwaterplanes = 0;
5691
5692                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5693
5694                 r_refdef.view.matrix = originalmatrix;
5695
5696                 CHECKGLERROR
5697                 return;
5698         }
5699
5700         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5701         {
5702                 r_refdef.view.matrix = originalmatrix;
5703                 return;
5704         }
5705
5706         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5707         if (v_isometric.integer && r_refdef.view.ismain)
5708                 V_MakeViewIsometric();
5709
5710         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5711
5712         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5713                 // in sRGB fallback, behave similar to true sRGB: convert this
5714                 // value from linear to sRGB
5715                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5716
5717         R_RenderView_UpdateViewVectors();
5718
5719         R_Shadow_UpdateWorldLightSelection();
5720
5721         // this will set up r_fb.rt_screen
5722         R_Bloom_StartFrame();
5723
5724         // apply bloom brightness offset
5725         if(r_fb.rt_bloom)
5726                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5727
5728         skipblend = R_BlendView_IsTrivial(r_fb.rt_screen->texturewidth, r_fb.rt_screen->textureheight, width, height);
5729         if (skipblend)
5730         {
5731                 // Render to the screen right away.
5732                 viewfbo = fbo;
5733                 viewdepthtexture = depthtexture;
5734                 viewcolortexture = colortexture;
5735                 viewx = x;
5736                 viewy = y;
5737                 viewwidth = width;
5738                 viewheight = height;
5739         }
5740         else if (r_fb.rt_screen)
5741         {
5742                 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5743                 viewfbo = r_fb.rt_screen->fbo;
5744                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5745                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5746                 viewx = 0;
5747                 viewy = 0;
5748                 viewwidth = r_fb.rt_screen->texturewidth;
5749                 viewheight = r_fb.rt_screen->textureheight;
5750         }
5751
5752         R_Water_StartFrame(viewwidth, viewheight);
5753
5754         CHECKGLERROR
5755         if (r_timereport_active)
5756                 R_TimeReport("viewsetup");
5757
5758         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5759
5760         // clear the whole fbo every frame - otherwise the driver will consider
5761         // it to be an inter-frame texture and stall in multi-gpu configurations
5762         if (r_fb.rt_screen)
5763                 GL_ScissorTest(false);
5764         R_ClearScreen(r_refdef.fogenabled);
5765         if (r_timereport_active)
5766                 R_TimeReport("viewclear");
5767
5768         r_refdef.view.clear = true;
5769
5770         r_refdef.view.showdebug = true;
5771
5772         R_View_Update(NULL);
5773         if (r_timereport_active)
5774                 R_TimeReport("visibility");
5775
5776         R_AnimCache_CacheVisibleEntities();
5777         if (r_timereport_active)
5778                 R_TimeReport("animcache");
5779
5780         R_Shadow_UpdateBounceGridTexture();
5781         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5782
5783         r_fb.water.numwaterplanes = 0;
5784         if (r_fb.water.enabled)
5785                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5786
5787         // for the actual view render we use scissoring a fair amount, so scissor
5788         // test needs to be on
5789         if (r_fb.rt_screen)
5790                 GL_ScissorTest(true);
5791         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5792         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5793         r_fb.water.numwaterplanes = 0;
5794
5795         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5796         GL_ScissorTest(false);
5797
5798         R_MotionBlurView(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5799         if (!skipblend)
5800                 R_BlendView(viewcolortexture, fbo, depthtexture, colortexture, x, y, width, height);
5801         if (r_timereport_active)
5802                 R_TimeReport("blendview");
5803
5804         r_refdef.view.matrix = originalmatrix;
5805
5806         CHECKGLERROR
5807
5808         // go back to 2d rendering
5809         DrawQ_Start();
5810 }
5811
5812 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5813 {
5814         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5815         {
5816                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5817                 if (r_timereport_active)
5818                         R_TimeReport("waterworld");
5819         }
5820
5821         // don't let sound skip if going slow
5822         if (r_refdef.scene.extraupdate)
5823                 S_ExtraUpdate ();
5824
5825         R_DrawModelsAddWaterPlanes();
5826         if (r_timereport_active)
5827                 R_TimeReport("watermodels");
5828
5829         if (r_fb.water.numwaterplanes)
5830         {
5831                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5832                 if (r_timereport_active)
5833                         R_TimeReport("waterscenes");
5834         }
5835 }
5836
5837 extern cvar_t cl_locs_show;
5838 static void R_DrawLocs(void);
5839 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5840 static void R_DrawModelDecals(void);
5841 extern qbool r_shadow_usingdeferredprepass;
5842 extern int r_shadow_shadowmapatlas_modelshadows_size;
5843 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5844 {
5845         qbool shadowmapping = false;
5846
5847         if (r_timereport_active)
5848                 R_TimeReport("beginscene");
5849
5850         r_refdef.stats[r_stat_renders]++;
5851
5852         R_UpdateFog();
5853
5854         // don't let sound skip if going slow
5855         if (r_refdef.scene.extraupdate)
5856                 S_ExtraUpdate ();
5857
5858         R_MeshQueue_BeginScene();
5859
5860         R_SkyStartFrame();
5861
5862         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);
5863
5864         if (r_timereport_active)
5865                 R_TimeReport("skystartframe");
5866
5867         if (cl.csqc_vidvars.drawworld)
5868         {
5869                 // don't let sound skip if going slow
5870                 if (r_refdef.scene.extraupdate)
5871                         S_ExtraUpdate ();
5872
5873                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5874                 {
5875                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5876                         if (r_timereport_active)
5877                                 R_TimeReport("worldsky");
5878                 }
5879
5880                 if (R_DrawBrushModelsSky() && r_timereport_active)
5881                         R_TimeReport("bmodelsky");
5882
5883                 if (skyrendermasked && skyrenderlater)
5884                 {
5885                         // we have to force off the water clipping plane while rendering sky
5886                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5887                         R_Sky();
5888                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5889                         if (r_timereport_active)
5890                                 R_TimeReport("sky");
5891                 }
5892         }
5893
5894         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5895         r_shadow_viewfbo = viewfbo;
5896         r_shadow_viewdepthtexture = viewdepthtexture;
5897         r_shadow_viewcolortexture = viewcolortexture;
5898         r_shadow_viewx = viewx;
5899         r_shadow_viewy = viewy;
5900         r_shadow_viewwidth = viewwidth;
5901         r_shadow_viewheight = viewheight;
5902
5903         R_Shadow_PrepareModelShadows();
5904         R_Shadow_PrepareLights();
5905         if (r_timereport_active)
5906                 R_TimeReport("preparelights");
5907
5908         // render all the shadowmaps that will be used for this view
5909         shadowmapping = R_Shadow_ShadowMappingEnabled();
5910         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5911         {
5912                 R_Shadow_DrawShadowMaps();
5913                 if (r_timereport_active)
5914                         R_TimeReport("shadowmaps");
5915         }
5916
5917         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5918         if (r_shadow_usingdeferredprepass)
5919                 R_Shadow_DrawPrepass();
5920
5921         // now we begin the forward pass of the view render
5922         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5923         {
5924                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5925                 if (r_timereport_active)
5926                         R_TimeReport("worlddepth");
5927         }
5928         if (r_depthfirst.integer >= 2)
5929         {
5930                 R_DrawModelsDepth();
5931                 if (r_timereport_active)
5932                         R_TimeReport("modeldepth");
5933         }
5934
5935         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5936         {
5937                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5938                 if (r_timereport_active)
5939                         R_TimeReport("world");
5940         }
5941
5942         // don't let sound skip if going slow
5943         if (r_refdef.scene.extraupdate)
5944                 S_ExtraUpdate ();
5945
5946         R_DrawModels();
5947         if (r_timereport_active)
5948                 R_TimeReport("models");
5949
5950         // don't let sound skip if going slow
5951         if (r_refdef.scene.extraupdate)
5952                 S_ExtraUpdate ();
5953
5954         if (!r_shadow_usingdeferredprepass)
5955         {
5956                 R_Shadow_DrawLights();
5957                 if (r_timereport_active)
5958                         R_TimeReport("rtlights");
5959         }
5960
5961         // don't let sound skip if going slow
5962         if (r_refdef.scene.extraupdate)
5963                 S_ExtraUpdate ();
5964
5965         if (cl.csqc_vidvars.drawworld)
5966         {
5967                 R_DrawModelDecals();
5968                 if (r_timereport_active)
5969                         R_TimeReport("modeldecals");
5970
5971                 R_DrawParticles();
5972                 if (r_timereport_active)
5973                         R_TimeReport("particles");
5974
5975                 R_DrawExplosions();
5976                 if (r_timereport_active)
5977                         R_TimeReport("explosions");
5978         }
5979
5980         if (r_refdef.view.showdebug)
5981         {
5982                 if (cl_locs_show.integer)
5983                 {
5984                         R_DrawLocs();
5985                         if (r_timereport_active)
5986                                 R_TimeReport("showlocs");
5987                 }
5988
5989                 if (r_drawportals.integer)
5990                 {
5991                         R_DrawPortals();
5992                         if (r_timereport_active)
5993                                 R_TimeReport("portals");
5994                 }
5995
5996                 if (r_showbboxes_client.value > 0)
5997                 {
5998                         R_DrawEntityBBoxes(CLVM_prog);
5999                         if (r_timereport_active)
6000                                 R_TimeReport("clbboxes");
6001                 }
6002                 if (r_showbboxes.value > 0)
6003                 {
6004                         R_DrawEntityBBoxes(SVVM_prog);
6005                         if (r_timereport_active)
6006                                 R_TimeReport("svbboxes");
6007                 }
6008         }
6009
6010         if (r_transparent.integer)
6011         {
6012                 R_MeshQueue_RenderTransparent();
6013                 if (r_timereport_active)
6014                         R_TimeReport("drawtrans");
6015         }
6016
6017         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))
6018         {
6019                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6020                 if (r_timereport_active)
6021                         R_TimeReport("worlddebug");
6022                 R_DrawModelsDebug();
6023                 if (r_timereport_active)
6024                         R_TimeReport("modeldebug");
6025         }
6026
6027         if (cl.csqc_vidvars.drawworld)
6028         {
6029                 R_Shadow_DrawCoronas();
6030                 if (r_timereport_active)
6031                         R_TimeReport("coronas");
6032         }
6033
6034         // don't let sound skip if going slow
6035         if (r_refdef.scene.extraupdate)
6036                 S_ExtraUpdate ();
6037 }
6038
6039 static const unsigned short bboxelements[36] =
6040 {
6041         5, 1, 3, 5, 3, 7,
6042         6, 2, 0, 6, 0, 4,
6043         7, 3, 2, 7, 2, 6,
6044         4, 0, 1, 4, 1, 5,
6045         4, 5, 7, 4, 7, 6,
6046         1, 0, 2, 1, 2, 3,
6047 };
6048
6049 #define BBOXEDGES 13
6050 static const float bboxedges[BBOXEDGES][6] =
6051 {
6052         // whole box
6053         { 0, 0, 0, 1, 1, 1 },
6054         // bottom edges
6055         { 0, 0, 0, 0, 1, 0 },
6056         { 0, 0, 0, 1, 0, 0 },
6057         { 0, 1, 0, 1, 1, 0 },
6058         { 1, 0, 0, 1, 1, 0 },
6059         // top edges
6060         { 0, 0, 1, 0, 1, 1 },
6061         { 0, 0, 1, 1, 0, 1 },
6062         { 0, 1, 1, 1, 1, 1 },
6063         { 1, 0, 1, 1, 1, 1 },
6064         // vertical edges
6065         { 0, 0, 0, 0, 0, 1 },
6066         { 1, 0, 0, 1, 0, 1 },
6067         { 0, 1, 0, 0, 1, 1 },
6068         { 1, 1, 0, 1, 1, 1 },
6069 };
6070
6071 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6072 {
6073         int numvertices = BBOXEDGES * 8;
6074         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6075         int numtriangles = BBOXEDGES * 12;
6076         unsigned short elements[BBOXEDGES * 36];
6077         int i, edge;
6078         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6079
6080         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6081
6082         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6083         GL_DepthMask(false);
6084         GL_DepthRange(0, 1);
6085         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6086
6087         for (edge = 0; edge < BBOXEDGES; edge++)
6088         {
6089                 for (i = 0; i < 3; i++)
6090                 {
6091                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6092                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6093                 }
6094                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6095                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6096                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6097                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6098                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6099                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6100                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6101                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6102                 for (i = 0; i < 36; i++)
6103                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6104         }
6105         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6106         if (r_refdef.fogenabled)
6107         {
6108                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6109                 {
6110                         f1 = RSurf_FogVertex(v);
6111                         f2 = 1 - f1;
6112                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6113                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6114                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6115                 }
6116         }
6117         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6118         R_Mesh_ResetTextureState();
6119         R_SetupShader_Generic_NoTexture(false, false);
6120         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6121 }
6122
6123 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6124 {
6125         // hacky overloading of the parameters
6126         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6127         int i;
6128         float color[4];
6129         prvm_edict_t *edict;
6130
6131         GL_CullFace(GL_NONE);
6132         R_SetupShader_Generic_NoTexture(false, false);
6133
6134         for (i = 0;i < numsurfaces;i++)
6135         {
6136                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6137                 switch ((int)PRVM_serveredictfloat(edict, solid))
6138                 {
6139                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6140                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6141                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6142                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6143                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6144                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6145                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6146                 }
6147                 if (prog == CLVM_prog)
6148                         color[3] *= r_showbboxes_client.value;
6149                 else
6150                         color[3] *= r_showbboxes.value;
6151                 color[3] = bound(0, color[3], 1);
6152                 GL_DepthTest(!r_showdisabledepthtest.integer);
6153                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6154         }
6155 }
6156
6157 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6158 {
6159         int i;
6160         prvm_edict_t *edict;
6161         vec3_t center;
6162
6163         if (prog == NULL)
6164                 return;
6165
6166         for (i = 0; i < prog->num_edicts; i++)
6167         {
6168                 edict = PRVM_EDICT_NUM(i);
6169                 if (edict->free)
6170                         continue;
6171                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6172                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6173                         continue;
6174                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6175                         continue;
6176                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6177                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6178         }
6179 }
6180
6181 static const int nomodelelement3i[24] =
6182 {
6183         5, 2, 0,
6184         5, 1, 2,
6185         5, 0, 3,
6186         5, 3, 1,
6187         0, 2, 4,
6188         2, 1, 4,
6189         3, 0, 4,
6190         1, 3, 4
6191 };
6192
6193 static const unsigned short nomodelelement3s[24] =
6194 {
6195         5, 2, 0,
6196         5, 1, 2,
6197         5, 0, 3,
6198         5, 3, 1,
6199         0, 2, 4,
6200         2, 1, 4,
6201         3, 0, 4,
6202         1, 3, 4
6203 };
6204
6205 static const float nomodelvertex3f[6*3] =
6206 {
6207         -16,   0,   0,
6208          16,   0,   0,
6209           0, -16,   0,
6210           0,  16,   0,
6211           0,   0, -16,
6212           0,   0,  16
6213 };
6214
6215 static const float nomodelcolor4f[6*4] =
6216 {
6217         0.0f, 0.0f, 0.5f, 1.0f,
6218         0.0f, 0.0f, 0.5f, 1.0f,
6219         0.0f, 0.5f, 0.0f, 1.0f,
6220         0.0f, 0.5f, 0.0f, 1.0f,
6221         0.5f, 0.0f, 0.0f, 1.0f,
6222         0.5f, 0.0f, 0.0f, 1.0f
6223 };
6224
6225 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6226 {
6227         int i;
6228         float f1, f2, *c;
6229         float color4f[6*4];
6230
6231         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);
6232
6233         // this is only called once per entity so numsurfaces is always 1, and
6234         // surfacelist is always {0}, so this code does not handle batches
6235
6236         if (rsurface.ent_flags & RENDER_ADDITIVE)
6237         {
6238                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6239                 GL_DepthMask(false);
6240         }
6241         else if (ent->alpha < 1)
6242         {
6243                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6244                 GL_DepthMask(false);
6245         }
6246         else
6247         {
6248                 GL_BlendFunc(GL_ONE, GL_ZERO);
6249                 GL_DepthMask(true);
6250         }
6251         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6252         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6253         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6254         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6255         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6256         for (i = 0, c = color4f;i < 6;i++, c += 4)
6257         {
6258                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6259                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6260                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6261                 c[3] *= ent->alpha;
6262         }
6263         if (r_refdef.fogenabled)
6264         {
6265                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6266                 {
6267                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6268                         f2 = 1 - f1;
6269                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6270                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6271                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6272                 }
6273         }
6274 //      R_Mesh_ResetTextureState();
6275         R_SetupShader_Generic_NoTexture(false, false);
6276         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6277         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6278 }
6279
6280 void R_DrawNoModel(entity_render_t *ent)
6281 {
6282         vec3_t org;
6283         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6284         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6285                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6286         else
6287                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6288 }
6289
6290 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6291 {
6292         vec3_t right1, right2, diff, normal;
6293
6294         VectorSubtract (org2, org1, normal);
6295
6296         // calculate 'right' vector for start
6297         VectorSubtract (r_refdef.view.origin, org1, diff);
6298         CrossProduct (normal, diff, right1);
6299         VectorNormalize (right1);
6300
6301         // calculate 'right' vector for end
6302         VectorSubtract (r_refdef.view.origin, org2, diff);
6303         CrossProduct (normal, diff, right2);
6304         VectorNormalize (right2);
6305
6306         vert[ 0] = org1[0] + width * right1[0];
6307         vert[ 1] = org1[1] + width * right1[1];
6308         vert[ 2] = org1[2] + width * right1[2];
6309         vert[ 3] = org1[0] - width * right1[0];
6310         vert[ 4] = org1[1] - width * right1[1];
6311         vert[ 5] = org1[2] - width * right1[2];
6312         vert[ 6] = org2[0] - width * right2[0];
6313         vert[ 7] = org2[1] - width * right2[1];
6314         vert[ 8] = org2[2] - width * right2[2];
6315         vert[ 9] = org2[0] + width * right2[0];
6316         vert[10] = org2[1] + width * right2[1];
6317         vert[11] = org2[2] + width * right2[2];
6318 }
6319
6320 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)
6321 {
6322         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6323         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6324         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6325         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6326         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6327         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6328         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6329         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6330         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6331         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6332         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6333         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6334 }
6335
6336 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6337 {
6338         int i;
6339         float *vertex3f;
6340         float v[3];
6341         VectorSet(v, x, y, z);
6342         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6343                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6344                         break;
6345         if (i == mesh->numvertices)
6346         {
6347                 if (mesh->numvertices < mesh->maxvertices)
6348                 {
6349                         VectorCopy(v, vertex3f);
6350                         mesh->numvertices++;
6351                 }
6352                 return mesh->numvertices;
6353         }
6354         else
6355                 return i;
6356 }
6357
6358 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6359 {
6360         int i;
6361         int *e, element[3];
6362         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6363         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6364         e = mesh->element3i + mesh->numtriangles * 3;
6365         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6366         {
6367                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6368                 if (mesh->numtriangles < mesh->maxtriangles)
6369                 {
6370                         *e++ = element[0];
6371                         *e++ = element[1];
6372                         *e++ = element[2];
6373                         mesh->numtriangles++;
6374                 }
6375                 element[1] = element[2];
6376         }
6377 }
6378
6379 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6380 {
6381         int i;
6382         int *e, element[3];
6383         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6384         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6385         e = mesh->element3i + mesh->numtriangles * 3;
6386         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6387         {
6388                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6389                 if (mesh->numtriangles < mesh->maxtriangles)
6390                 {
6391                         *e++ = element[0];
6392                         *e++ = element[1];
6393                         *e++ = element[2];
6394                         mesh->numtriangles++;
6395                 }
6396                 element[1] = element[2];
6397         }
6398 }
6399
6400 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6401 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6402 {
6403         int planenum, planenum2;
6404         int w;
6405         int tempnumpoints;
6406         mplane_t *plane, *plane2;
6407         double maxdist;
6408         double temppoints[2][256*3];
6409         // figure out how large a bounding box we need to properly compute this brush
6410         maxdist = 0;
6411         for (w = 0;w < numplanes;w++)
6412                 maxdist = max(maxdist, fabs(planes[w].dist));
6413         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6414         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6415         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6416         {
6417                 w = 0;
6418                 tempnumpoints = 4;
6419                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6420                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6421                 {
6422                         if (planenum2 == planenum)
6423                                 continue;
6424                         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);
6425                         w = !w;
6426                 }
6427                 if (tempnumpoints < 3)
6428                         continue;
6429                 // generate elements forming a triangle fan for this polygon
6430                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6431         }
6432 }
6433
6434 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6435 {
6436         if(parms[0] == 0 && parms[1] == 0)
6437                 return false;
6438         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6439                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6440                         return false;
6441         return true;
6442 }
6443
6444 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6445 {
6446         double index, f;
6447         index = parms[2] + rsurface.shadertime * parms[3];
6448         index -= floor(index);
6449         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6450         {
6451         default:
6452         case Q3WAVEFUNC_NONE:
6453         case Q3WAVEFUNC_NOISE:
6454         case Q3WAVEFUNC_COUNT:
6455                 f = 0;
6456                 break;
6457         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6458         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6459         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6460         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6461         case Q3WAVEFUNC_TRIANGLE:
6462                 index *= 4;
6463                 f = index - floor(index);
6464                 if (index < 1)
6465                 {
6466                         // f = f;
6467                 }
6468                 else if (index < 2)
6469                         f = 1 - f;
6470                 else if (index < 3)
6471                         f = -f;
6472                 else
6473                         f = -(1 - f);
6474                 break;
6475         }
6476         f = parms[0] + parms[1] * f;
6477         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6478                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6479         return (float) f;
6480 }
6481
6482 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6483 {
6484         int w, h, idx;
6485         float shadertime;
6486         float f;
6487         float offsetd[2];
6488         float tcmat[12];
6489         matrix4x4_t matrix, temp;
6490         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6491         // it's better to have one huge fixup every 9 hours than gradual
6492         // degradation over time which looks consistently bad after many hours.
6493         //
6494         // tcmod scroll in particular suffers from this degradation which can't be
6495         // effectively worked around even with floor() tricks because we don't
6496         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6497         // a workaround involving floor() would be incorrect anyway...
6498         shadertime = rsurface.shadertime;
6499         if (shadertime >= 32768.0f)
6500                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6501         switch(tcmod->tcmod)
6502         {
6503                 case Q3TCMOD_COUNT:
6504                 case Q3TCMOD_NONE:
6505                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6506                                 matrix = r_waterscrollmatrix;
6507                         else
6508                                 matrix = identitymatrix;
6509                         break;
6510                 case Q3TCMOD_ENTITYTRANSLATE:
6511                         // this is used in Q3 to allow the gamecode to control texcoord
6512                         // scrolling on the entity, which is not supported in darkplaces yet.
6513                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6514                         break;
6515                 case Q3TCMOD_ROTATE:
6516                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6517                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6518                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6519                         break;
6520                 case Q3TCMOD_SCALE:
6521                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6522                         break;
6523                 case Q3TCMOD_SCROLL:
6524                         // this particular tcmod is a "bug for bug" compatible one with regards to
6525                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6526                         // specifically did the wrapping and so we must mimic that...
6527                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6528                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6529                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6530                         break;
6531                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6532                         w = (int) tcmod->parms[0];
6533                         h = (int) tcmod->parms[1];
6534                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6535                         f = f - floor(f);
6536                         idx = (int) floor(f * w * h);
6537                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6538                         break;
6539                 case Q3TCMOD_STRETCH:
6540                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6541                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6542                         break;
6543                 case Q3TCMOD_TRANSFORM:
6544                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6545                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6546                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6547                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6548                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6549                         break;
6550                 case Q3TCMOD_TURBULENT:
6551                         // this is handled in the RSurf_PrepareVertices function
6552                         matrix = identitymatrix;
6553                         break;
6554         }
6555         temp = *texmatrix;
6556         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6557 }
6558
6559 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6560 {
6561         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6562         char name[MAX_QPATH];
6563         skinframe_t *skinframe;
6564         unsigned char pixels[296*194];
6565         dp_strlcpy(cache->name, skinname, sizeof(cache->name));
6566         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6567         if (developer_loading.integer)
6568                 Con_Printf("loading %s\n", name);
6569         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6570         if (!skinframe || !skinframe->base)
6571         {
6572                 unsigned char *f;
6573                 fs_offset_t filesize;
6574                 skinframe = NULL;
6575                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6576                 if (f)
6577                 {
6578                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6579                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6580                         Mem_Free(f);
6581                 }
6582         }
6583         cache->skinframe = skinframe;
6584 }
6585
6586 texture_t *R_GetCurrentTexture(texture_t *t)
6587 {
6588         int i, q;
6589         const entity_render_t *ent = rsurface.entity;
6590         model_t *model = ent->model; // when calling this, ent must not be NULL
6591         q3shaderinfo_layer_tcmod_t *tcmod;
6592         float specularscale = 0.0f;
6593
6594         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6595                 return t->currentframe;
6596         t->update_lastrenderframe = r_textureframe;
6597         t->update_lastrenderentity = (void *)ent;
6598
6599         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6600                 t->camera_entity = ent->entitynumber;
6601         else
6602                 t->camera_entity = 0;
6603
6604         // switch to an alternate material if this is a q1bsp animated material
6605         {
6606                 texture_t *texture = t;
6607                 int s = rsurface.ent_skinnum;
6608                 if ((unsigned int)s >= (unsigned int)model->numskins)
6609                         s = 0;
6610                 if (model->skinscenes)
6611                 {
6612                         if (model->skinscenes[s].framecount > 1)
6613                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6614                         else
6615                                 s = model->skinscenes[s].firstframe;
6616                 }
6617                 if (s > 0)
6618                         t = t + s * model->num_surfaces;
6619                 if (t->animated)
6620                 {
6621                         // use an alternate animation if the entity's frame is not 0,
6622                         // and only if the texture has an alternate animation
6623                         if (t->animated == 2) // q2bsp
6624                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6625                         else if (rsurface.ent_alttextures && t->anim_total[1])
6626                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6627                         else
6628                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6629                 }
6630                 texture->currentframe = t;
6631         }
6632
6633         // update currentskinframe to be a qw skin or animation frame
6634         if (rsurface.ent_qwskin >= 0)
6635         {
6636                 i = rsurface.ent_qwskin;
6637                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6638                 {
6639                         r_qwskincache_size = cl.maxclients;
6640                         if (r_qwskincache)
6641                                 Mem_Free(r_qwskincache);
6642                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6643                 }
6644                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6645                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6646                 t->currentskinframe = r_qwskincache[i].skinframe;
6647                 if (t->materialshaderpass && t->currentskinframe == NULL)
6648                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6649         }
6650         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6651                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6652         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6653                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6654
6655         t->currentmaterialflags = t->basematerialflags;
6656         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6657         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6658                 t->currentalpha *= r_wateralpha.value;
6659         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6660                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6661         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6662                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6663
6664         // decide on which type of lighting to use for this surface
6665         if (rsurface.entity->render_modellight_forced)
6666                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6667         if (rsurface.entity->render_rtlight_disabled)
6668                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6669         if (rsurface.entity->render_lightgrid)
6670                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6671         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6672         {
6673                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6674                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6675                 for (q = 0; q < 3; q++)
6676                 {
6677                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6678                         t->render_modellight_lightdir_world[q] = q == 2;
6679                         t->render_modellight_lightdir_local[q] = q == 2;
6680                         t->render_modellight_ambient[q] = 1;
6681                         t->render_modellight_diffuse[q] = 0;
6682                         t->render_modellight_specular[q] = 0;
6683                         t->render_lightmap_ambient[q] = 0;
6684                         t->render_lightmap_diffuse[q] = 0;
6685                         t->render_lightmap_specular[q] = 0;
6686                         t->render_rtlight_diffuse[q] = 0;
6687                         t->render_rtlight_specular[q] = 0;
6688                 }
6689         }
6690         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6691         {
6692                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6693                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6694                 for (q = 0; q < 3; q++)
6695                 {
6696                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6697                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6698                         t->render_modellight_lightdir_world[q] = q == 2;
6699                         t->render_modellight_lightdir_local[q] = q == 2;
6700                         t->render_modellight_diffuse[q] = 0;
6701                         t->render_modellight_specular[q] = 0;
6702                         t->render_lightmap_ambient[q] = 0;
6703                         t->render_lightmap_diffuse[q] = 0;
6704                         t->render_lightmap_specular[q] = 0;
6705                         t->render_rtlight_diffuse[q] = 0;
6706                         t->render_rtlight_specular[q] = 0;
6707                 }
6708         }
6709         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6710         {
6711                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6712                 for (q = 0; q < 3; q++)
6713                 {
6714                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6715                         t->render_modellight_lightdir_world[q] = q == 2;
6716                         t->render_modellight_lightdir_local[q] = q == 2;
6717                         t->render_modellight_ambient[q] = 0;
6718                         t->render_modellight_diffuse[q] = 0;
6719                         t->render_modellight_specular[q] = 0;
6720                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6721                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6722                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6723                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6724                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6725                 }
6726         }
6727         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6728         {
6729                 // ambient + single direction light (modellight)
6730                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6731                 for (q = 0; q < 3; q++)
6732                 {
6733                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6734                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6735                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6736                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6737                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6738                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6739                         t->render_lightmap_ambient[q] = 0;
6740                         t->render_lightmap_diffuse[q] = 0;
6741                         t->render_lightmap_specular[q] = 0;
6742                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6743                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6744                 }
6745         }
6746         else
6747         {
6748                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6749                 for (q = 0; q < 3; q++)
6750                 {
6751                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6752                         t->render_modellight_lightdir_world[q] = q == 2;
6753                         t->render_modellight_lightdir_local[q] = q == 2;
6754                         t->render_modellight_ambient[q] = 0;
6755                         t->render_modellight_diffuse[q] = 0;
6756                         t->render_modellight_specular[q] = 0;
6757                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6758                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6759                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6760                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6761                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6762                 }
6763         }
6764
6765         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6766         {
6767                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6768                 // attribute, we punt it to the lightmap path and hope for the best,
6769                 // but lighting doesn't work.
6770                 //
6771                 // FIXME: this is fine for effects but CSQC polygons should be subject
6772                 // to lighting.
6773                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6774                 for (q = 0; q < 3; q++)
6775                 {
6776                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6777                         t->render_modellight_lightdir_world[q] = q == 2;
6778                         t->render_modellight_lightdir_local[q] = q == 2;
6779                         t->render_modellight_ambient[q] = 0;
6780                         t->render_modellight_diffuse[q] = 0;
6781                         t->render_modellight_specular[q] = 0;
6782                         t->render_lightmap_ambient[q] = 0;
6783                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6784                         t->render_lightmap_specular[q] = 0;
6785                         t->render_rtlight_diffuse[q] = 0;
6786                         t->render_rtlight_specular[q] = 0;
6787                 }
6788         }
6789
6790         for (q = 0; q < 3; q++)
6791         {
6792                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6793                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6794         }
6795
6796         if (rsurface.ent_flags & RENDER_ADDITIVE)
6797                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6798         else if (t->currentalpha < 1)
6799                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6800         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6801         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6802                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6803         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6804                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6805         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6806                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6807         if (t->backgroundshaderpass)
6808                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6809         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6810         {
6811                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6812                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6813         }
6814         else
6815                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6816         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6817         {
6818                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6819                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6820         }
6821         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6822                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6823
6824         // there is no tcmod
6825         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6826         {
6827                 t->currenttexmatrix = r_waterscrollmatrix;
6828                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6829         }
6830         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6831         {
6832                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6833                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6834         }
6835
6836         if (t->materialshaderpass)
6837                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6838                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6839
6840         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6841         if (t->currentskinframe->qpixels)
6842                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6843         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6844         if (!t->basetexture)
6845                 t->basetexture = r_texture_notexture;
6846         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6847         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6848         t->nmaptexture = t->currentskinframe->nmap;
6849         if (!t->nmaptexture)
6850                 t->nmaptexture = r_texture_blanknormalmap;
6851         t->glosstexture = r_texture_black;
6852         t->glowtexture = t->currentskinframe->glow;
6853         t->fogtexture = t->currentskinframe->fog;
6854         t->reflectmasktexture = t->currentskinframe->reflect;
6855         if (t->backgroundshaderpass)
6856         {
6857                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6858                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6859                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6860                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6861                 t->backgroundglosstexture = r_texture_black;
6862                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6863                 if (!t->backgroundnmaptexture)
6864                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6865                 // make sure that if glow is going to be used, both textures are not NULL
6866                 if (!t->backgroundglowtexture && t->glowtexture)
6867                         t->backgroundglowtexture = r_texture_black;
6868                 if (!t->glowtexture && t->backgroundglowtexture)
6869                         t->glowtexture = r_texture_black;
6870         }
6871         else
6872         {
6873                 t->backgroundbasetexture = r_texture_white;
6874                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6875                 t->backgroundglosstexture = r_texture_black;
6876                 t->backgroundglowtexture = NULL;
6877         }
6878         t->specularpower = r_shadow_glossexponent.value;
6879         // TODO: store reference values for these in the texture?
6880         if (r_shadow_gloss.integer > 0)
6881         {
6882                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6883                 {
6884                         if (r_shadow_glossintensity.value > 0)
6885                         {
6886                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6887                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6888                                 specularscale = r_shadow_glossintensity.value;
6889                         }
6890                 }
6891                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6892                 {
6893                         t->glosstexture = r_texture_white;
6894                         t->backgroundglosstexture = r_texture_white;
6895                         specularscale = r_shadow_gloss2intensity.value;
6896                         t->specularpower = r_shadow_gloss2exponent.value;
6897                 }
6898         }
6899         specularscale *= t->specularscalemod;
6900         t->specularpower *= t->specularpowermod;
6901
6902         // lightmaps mode looks bad with dlights using actual texturing, so turn
6903         // off the colormap and glossmap, but leave the normalmap on as it still
6904         // accurately represents the shading involved
6905         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6906         {
6907                 t->basetexture = r_texture_grey128;
6908                 t->pantstexture = r_texture_black;
6909                 t->shirttexture = r_texture_black;
6910                 if (gl_lightmaps.integer < 2)
6911                         t->nmaptexture = r_texture_blanknormalmap;
6912                 t->glosstexture = r_texture_black;
6913                 t->glowtexture = NULL;
6914                 t->fogtexture = NULL;
6915                 t->reflectmasktexture = NULL;
6916                 t->backgroundbasetexture = NULL;
6917                 if (gl_lightmaps.integer < 2)
6918                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6919                 t->backgroundglosstexture = r_texture_black;
6920                 t->backgroundglowtexture = NULL;
6921                 specularscale = 0;
6922                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6923         }
6924
6925         if (specularscale != 1.0f)
6926         {
6927                 for (q = 0; q < 3; q++)
6928                 {
6929                         t->render_modellight_specular[q] *= specularscale;
6930                         t->render_lightmap_specular[q] *= specularscale;
6931                         t->render_rtlight_specular[q] *= specularscale;
6932                 }
6933         }
6934
6935         t->currentblendfunc[0] = GL_ONE;
6936         t->currentblendfunc[1] = GL_ZERO;
6937         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6938         {
6939                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6940                 t->currentblendfunc[1] = GL_ONE;
6941         }
6942         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6943         {
6944                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6945                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6946         }
6947         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6948         {
6949                 t->currentblendfunc[0] = t->customblendfunc[0];
6950                 t->currentblendfunc[1] = t->customblendfunc[1];
6951         }
6952
6953         return t;
6954 }
6955
6956 rsurfacestate_t rsurface;
6957
6958 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6959 {
6960         model_t *model = ent->model;
6961         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6962         //      return;
6963         rsurface.entity = (entity_render_t *)ent;
6964         rsurface.skeleton = ent->skeleton;
6965         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6966         rsurface.ent_skinnum = ent->skinnum;
6967         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;
6968         rsurface.ent_flags = ent->flags;
6969         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6970                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6971         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6972         rsurface.matrix = ent->matrix;
6973         rsurface.inversematrix = ent->inversematrix;
6974         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6975         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6976         R_EntityMatrix(&rsurface.matrix);
6977         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6978         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6979         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6980         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6981         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6982         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6983         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6984         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6985         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6986         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6987         if (ent->model->brush.submodel && !prepass)
6988         {
6989                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6990                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6991         }
6992         // if the animcache code decided it should use the shader path, skip the deform step
6993         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6994         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6995         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6996         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6997         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6998         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6999         {
7000                 if (ent->animcache_vertex3f)
7001                 {
7002                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7003                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7004                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7005                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7006                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7007                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7008                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7009                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7010                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7011                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7012                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7013                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7014                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7015                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7016                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7017                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7018                 }
7019                 else if (wanttangents)
7020                 {
7021                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7022                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7023                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7024                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7025                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7026                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7027                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7028                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7029                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7030                         rsurface.modelvertex3f_vertexbuffer = NULL;
7031                         rsurface.modelvertex3f_bufferoffset = 0;
7032                         rsurface.modelvertex3f_vertexbuffer = 0;
7033                         rsurface.modelvertex3f_bufferoffset = 0;
7034                         rsurface.modelsvector3f_vertexbuffer = 0;
7035                         rsurface.modelsvector3f_bufferoffset = 0;
7036                         rsurface.modeltvector3f_vertexbuffer = 0;
7037                         rsurface.modeltvector3f_bufferoffset = 0;
7038                         rsurface.modelnormal3f_vertexbuffer = 0;
7039                         rsurface.modelnormal3f_bufferoffset = 0;
7040                 }
7041                 else if (wantnormals)
7042                 {
7043                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7044                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7045                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7046                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7047                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7048                         rsurface.modelsvector3f = NULL;
7049                         rsurface.modeltvector3f = NULL;
7050                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7051                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7052                         rsurface.modelvertex3f_vertexbuffer = NULL;
7053                         rsurface.modelvertex3f_bufferoffset = 0;
7054                         rsurface.modelvertex3f_vertexbuffer = 0;
7055                         rsurface.modelvertex3f_bufferoffset = 0;
7056                         rsurface.modelsvector3f_vertexbuffer = 0;
7057                         rsurface.modelsvector3f_bufferoffset = 0;
7058                         rsurface.modeltvector3f_vertexbuffer = 0;
7059                         rsurface.modeltvector3f_bufferoffset = 0;
7060                         rsurface.modelnormal3f_vertexbuffer = 0;
7061                         rsurface.modelnormal3f_bufferoffset = 0;
7062                 }
7063                 else
7064                 {
7065                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7066                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7067                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7068                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7069                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7070                         rsurface.modelsvector3f = NULL;
7071                         rsurface.modeltvector3f = NULL;
7072                         rsurface.modelnormal3f = NULL;
7073                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7074                         rsurface.modelvertex3f_vertexbuffer = NULL;
7075                         rsurface.modelvertex3f_bufferoffset = 0;
7076                         rsurface.modelvertex3f_vertexbuffer = 0;
7077                         rsurface.modelvertex3f_bufferoffset = 0;
7078                         rsurface.modelsvector3f_vertexbuffer = 0;
7079                         rsurface.modelsvector3f_bufferoffset = 0;
7080                         rsurface.modeltvector3f_vertexbuffer = 0;
7081                         rsurface.modeltvector3f_bufferoffset = 0;
7082                         rsurface.modelnormal3f_vertexbuffer = 0;
7083                         rsurface.modelnormal3f_bufferoffset = 0;
7084                 }
7085                 rsurface.modelgeneratedvertex = true;
7086         }
7087         else
7088         {
7089                 if (rsurface.entityskeletaltransform3x4)
7090                 {
7091                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7092                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7093                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7094                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7095                 }
7096                 else
7097                 {
7098                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7099                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7100                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7101                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7102                 }
7103                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7104                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7105                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7106                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7107                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7108                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7109                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7110                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7111                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7112                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7113                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7114                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7115                 rsurface.modelgeneratedvertex = false;
7116         }
7117         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7118         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7119         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7120         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7121         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7122         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7123         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7124         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7125         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7126         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7127         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7128         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7129         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7130         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7131         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7132         rsurface.modelelement3i = model->surfmesh.data_element3i;
7133         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7134         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7135         rsurface.modelelement3s = model->surfmesh.data_element3s;
7136         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7137         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7138         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7139         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7140         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7141         rsurface.modelsurfaces = model->data_surfaces;
7142         rsurface.batchgeneratedvertex = false;
7143         rsurface.batchfirstvertex = 0;
7144         rsurface.batchnumvertices = 0;
7145         rsurface.batchfirsttriangle = 0;
7146         rsurface.batchnumtriangles = 0;
7147         rsurface.batchvertex3f  = NULL;
7148         rsurface.batchvertex3f_vertexbuffer = NULL;
7149         rsurface.batchvertex3f_bufferoffset = 0;
7150         rsurface.batchsvector3f = NULL;
7151         rsurface.batchsvector3f_vertexbuffer = NULL;
7152         rsurface.batchsvector3f_bufferoffset = 0;
7153         rsurface.batchtvector3f = NULL;
7154         rsurface.batchtvector3f_vertexbuffer = NULL;
7155         rsurface.batchtvector3f_bufferoffset = 0;
7156         rsurface.batchnormal3f  = NULL;
7157         rsurface.batchnormal3f_vertexbuffer = NULL;
7158         rsurface.batchnormal3f_bufferoffset = 0;
7159         rsurface.batchlightmapcolor4f = NULL;
7160         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7161         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7162         rsurface.batchtexcoordtexture2f = NULL;
7163         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7164         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7165         rsurface.batchtexcoordlightmap2f = NULL;
7166         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7167         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7168         rsurface.batchskeletalindex4ub = NULL;
7169         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7170         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7171         rsurface.batchskeletalweight4ub = NULL;
7172         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7173         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7174         rsurface.batchelement3i = NULL;
7175         rsurface.batchelement3i_indexbuffer = NULL;
7176         rsurface.batchelement3i_bufferoffset = 0;
7177         rsurface.batchelement3s = NULL;
7178         rsurface.batchelement3s_indexbuffer = NULL;
7179         rsurface.batchelement3s_bufferoffset = 0;
7180         rsurface.forcecurrenttextureupdate = false;
7181 }
7182
7183 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)
7184 {
7185         rsurface.entity = r_refdef.scene.worldentity;
7186         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7187                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7188                 // A better approach could be making this copy only once per frame.
7189                 static entity_render_t custom_entity;
7190                 int q;
7191                 custom_entity = *rsurface.entity;
7192                 for (q = 0; q < 3; ++q) {
7193                         float colormod = q == 0 ? r : q == 1 ? g : b;
7194                         custom_entity.render_fullbright[q] *= colormod;
7195                         custom_entity.render_modellight_ambient[q] *= colormod;
7196                         custom_entity.render_modellight_diffuse[q] *= colormod;
7197                         custom_entity.render_lightmap_ambient[q] *= colormod;
7198                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7199                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7200                 }
7201                 custom_entity.alpha *= a;
7202                 rsurface.entity = &custom_entity;
7203         }
7204         rsurface.skeleton = NULL;
7205         rsurface.ent_skinnum = 0;
7206         rsurface.ent_qwskin = -1;
7207         rsurface.ent_flags = entflags;
7208         rsurface.shadertime = r_refdef.scene.time - shadertime;
7209         rsurface.modelnumvertices = numvertices;
7210         rsurface.modelnumtriangles = numtriangles;
7211         rsurface.matrix = *matrix;
7212         rsurface.inversematrix = *inversematrix;
7213         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7214         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7215         R_EntityMatrix(&rsurface.matrix);
7216         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7217         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7218         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7219         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7220         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7221         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7222         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7223         rsurface.frameblend[0].lerp = 1;
7224         rsurface.ent_alttextures = false;
7225         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7226         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7227         rsurface.entityskeletaltransform3x4 = NULL;
7228         rsurface.entityskeletaltransform3x4buffer = NULL;
7229         rsurface.entityskeletaltransform3x4offset = 0;
7230         rsurface.entityskeletaltransform3x4size = 0;
7231         rsurface.entityskeletalnumtransforms = 0;
7232         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7233         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7234         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7235         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7236         if (wanttangents)
7237         {
7238                 rsurface.modelvertex3f = (float *)vertex3f;
7239                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7240                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7241                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7242         }
7243         else if (wantnormals)
7244         {
7245                 rsurface.modelvertex3f = (float *)vertex3f;
7246                 rsurface.modelsvector3f = NULL;
7247                 rsurface.modeltvector3f = NULL;
7248                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7249         }
7250         else
7251         {
7252                 rsurface.modelvertex3f = (float *)vertex3f;
7253                 rsurface.modelsvector3f = NULL;
7254                 rsurface.modeltvector3f = NULL;
7255                 rsurface.modelnormal3f = NULL;
7256         }
7257         rsurface.modelvertex3f_vertexbuffer = 0;
7258         rsurface.modelvertex3f_bufferoffset = 0;
7259         rsurface.modelsvector3f_vertexbuffer = 0;
7260         rsurface.modelsvector3f_bufferoffset = 0;
7261         rsurface.modeltvector3f_vertexbuffer = 0;
7262         rsurface.modeltvector3f_bufferoffset = 0;
7263         rsurface.modelnormal3f_vertexbuffer = 0;
7264         rsurface.modelnormal3f_bufferoffset = 0;
7265         rsurface.modelgeneratedvertex = true;
7266         rsurface.modellightmapcolor4f  = (float *)color4f;
7267         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7268         rsurface.modellightmapcolor4f_bufferoffset = 0;
7269         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7270         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7271         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7272         rsurface.modeltexcoordlightmap2f  = NULL;
7273         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7274         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7275         rsurface.modelskeletalindex4ub = NULL;
7276         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7277         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7278         rsurface.modelskeletalweight4ub = NULL;
7279         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7280         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7281         rsurface.modelelement3i = (int *)element3i;
7282         rsurface.modelelement3i_indexbuffer = NULL;
7283         rsurface.modelelement3i_bufferoffset = 0;
7284         rsurface.modelelement3s = (unsigned short *)element3s;
7285         rsurface.modelelement3s_indexbuffer = NULL;
7286         rsurface.modelelement3s_bufferoffset = 0;
7287         rsurface.modellightmapoffsets = NULL;
7288         rsurface.modelsurfaces = NULL;
7289         rsurface.batchgeneratedvertex = false;
7290         rsurface.batchfirstvertex = 0;
7291         rsurface.batchnumvertices = 0;
7292         rsurface.batchfirsttriangle = 0;
7293         rsurface.batchnumtriangles = 0;
7294         rsurface.batchvertex3f  = NULL;
7295         rsurface.batchvertex3f_vertexbuffer = NULL;
7296         rsurface.batchvertex3f_bufferoffset = 0;
7297         rsurface.batchsvector3f = NULL;
7298         rsurface.batchsvector3f_vertexbuffer = NULL;
7299         rsurface.batchsvector3f_bufferoffset = 0;
7300         rsurface.batchtvector3f = NULL;
7301         rsurface.batchtvector3f_vertexbuffer = NULL;
7302         rsurface.batchtvector3f_bufferoffset = 0;
7303         rsurface.batchnormal3f  = NULL;
7304         rsurface.batchnormal3f_vertexbuffer = NULL;
7305         rsurface.batchnormal3f_bufferoffset = 0;
7306         rsurface.batchlightmapcolor4f = NULL;
7307         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7308         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7309         rsurface.batchtexcoordtexture2f = NULL;
7310         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7311         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7312         rsurface.batchtexcoordlightmap2f = NULL;
7313         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7314         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7315         rsurface.batchskeletalindex4ub = NULL;
7316         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7317         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7318         rsurface.batchskeletalweight4ub = NULL;
7319         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7320         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7321         rsurface.batchelement3i = NULL;
7322         rsurface.batchelement3i_indexbuffer = NULL;
7323         rsurface.batchelement3i_bufferoffset = 0;
7324         rsurface.batchelement3s = NULL;
7325         rsurface.batchelement3s_indexbuffer = NULL;
7326         rsurface.batchelement3s_bufferoffset = 0;
7327         rsurface.forcecurrenttextureupdate = true;
7328
7329         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7330         {
7331                 if ((wantnormals || wanttangents) && !normal3f)
7332                 {
7333                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7334                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7335                 }
7336                 if (wanttangents && !svector3f)
7337                 {
7338                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7339                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7340                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7341                 }
7342         }
7343 }
7344
7345 float RSurf_FogPoint(const float *v)
7346 {
7347         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7348         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7349         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7350         float FogHeightFade = r_refdef.fogheightfade;
7351         float fogfrac;
7352         unsigned int fogmasktableindex;
7353         if (r_refdef.fogplaneviewabove)
7354                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7355         else
7356                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7357         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7358         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7359 }
7360
7361 float RSurf_FogVertex(const float *v)
7362 {
7363         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7364         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7365         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7366         float FogHeightFade = rsurface.fogheightfade;
7367         float fogfrac;
7368         unsigned int fogmasktableindex;
7369         if (r_refdef.fogplaneviewabove)
7370                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7371         else
7372                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7373         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7374         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7375 }
7376
7377 void RSurf_UploadBuffersForBatch(void)
7378 {
7379         // 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)
7380         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7381         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7382                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7383         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7384                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7385         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7386                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7387         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7388                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7389         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7390                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7391         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7392                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7393         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7394                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7395         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7396                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7397         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7398                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7399
7400         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7401                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7402         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7403                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7404
7405         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7406         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7407         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7408         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7409         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7410         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7411         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7412         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7413         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7414         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7415 }
7416
7417 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7418 {
7419         int i;
7420         for (i = 0;i < numelements;i++)
7421                 outelement3i[i] = inelement3i[i] + adjust;
7422 }
7423
7424 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7425 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7426 {
7427         int deformindex;
7428         int firsttriangle;
7429         int numtriangles;
7430         int firstvertex;
7431         int endvertex;
7432         int numvertices;
7433         int surfacefirsttriangle;
7434         int surfacenumtriangles;
7435         int surfacefirstvertex;
7436         int surfaceendvertex;
7437         int surfacenumvertices;
7438         int batchnumsurfaces = texturenumsurfaces;
7439         int batchnumvertices;
7440         int batchnumtriangles;
7441         int i, j;
7442         qbool gaps;
7443         qbool dynamicvertex;
7444         float amplitude;
7445         float animpos;
7446         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7447         float waveparms[4];
7448         unsigned char *ub;
7449         q3shaderinfo_deform_t *deform;
7450         const msurface_t *surface, *firstsurface;
7451         if (!texturenumsurfaces)
7452                 return;
7453         // find vertex range of this surface batch
7454         gaps = false;
7455         firstsurface = texturesurfacelist[0];
7456         firsttriangle = firstsurface->num_firsttriangle;
7457         batchnumvertices = 0;
7458         batchnumtriangles = 0;
7459         firstvertex = endvertex = firstsurface->num_firstvertex;
7460         for (i = 0;i < texturenumsurfaces;i++)
7461         {
7462                 surface = texturesurfacelist[i];
7463                 if (surface != firstsurface + i)
7464                         gaps = true;
7465                 surfacefirstvertex = surface->num_firstvertex;
7466                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7467                 surfacenumvertices = surface->num_vertices;
7468                 surfacenumtriangles = surface->num_triangles;
7469                 if (firstvertex > surfacefirstvertex)
7470                         firstvertex = surfacefirstvertex;
7471                 if (endvertex < surfaceendvertex)
7472                         endvertex = surfaceendvertex;
7473                 batchnumvertices += surfacenumvertices;
7474                 batchnumtriangles += surfacenumtriangles;
7475         }
7476
7477         r_refdef.stats[r_stat_batch_batches]++;
7478         if (gaps)
7479                 r_refdef.stats[r_stat_batch_withgaps]++;
7480         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7481         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7482         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7483
7484         // we now know the vertex range used, and if there are any gaps in it
7485         rsurface.batchfirstvertex = firstvertex;
7486         rsurface.batchnumvertices = endvertex - firstvertex;
7487         rsurface.batchfirsttriangle = firsttriangle;
7488         rsurface.batchnumtriangles = batchnumtriangles;
7489
7490         // check if any dynamic vertex processing must occur
7491         dynamicvertex = false;
7492
7493         // we must use vertexbuffers for rendering, we can upload vertex buffers
7494         // easily enough but if the basevertex is non-zero it becomes more
7495         // difficult, so force dynamicvertex path in that case - it's suboptimal
7496         // but the most optimal case is to have the geometry sources provide their
7497         // own anyway.
7498         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7499                 dynamicvertex = true;
7500
7501         // a cvar to force the dynamic vertex path to be taken, for debugging
7502         if (r_batch_debugdynamicvertexpath.integer)
7503         {
7504                 if (!dynamicvertex)
7505                 {
7506                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7507                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7508                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7509                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7510                 }
7511                 dynamicvertex = true;
7512         }
7513
7514         // if there is a chance of animated vertex colors, it's a dynamic batch
7515         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7516         {
7517                 if (!dynamicvertex)
7518                 {
7519                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7520                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7521                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7522                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7523                 }
7524                 dynamicvertex = true;
7525         }
7526
7527         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7528         {
7529                 switch (deform->deform)
7530                 {
7531                 default:
7532                 case Q3DEFORM_PROJECTIONSHADOW:
7533                 case Q3DEFORM_TEXT0:
7534                 case Q3DEFORM_TEXT1:
7535                 case Q3DEFORM_TEXT2:
7536                 case Q3DEFORM_TEXT3:
7537                 case Q3DEFORM_TEXT4:
7538                 case Q3DEFORM_TEXT5:
7539                 case Q3DEFORM_TEXT6:
7540                 case Q3DEFORM_TEXT7:
7541                 case Q3DEFORM_NONE:
7542                         break;
7543                 case Q3DEFORM_AUTOSPRITE:
7544                         if (!dynamicvertex)
7545                         {
7546                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7547                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7548                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7549                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7550                         }
7551                         dynamicvertex = true;
7552                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7553                         break;
7554                 case Q3DEFORM_AUTOSPRITE2:
7555                         if (!dynamicvertex)
7556                         {
7557                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7558                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7559                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7560                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7561                         }
7562                         dynamicvertex = true;
7563                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7564                         break;
7565                 case Q3DEFORM_NORMAL:
7566                         if (!dynamicvertex)
7567                         {
7568                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7569                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7570                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7571                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7572                         }
7573                         dynamicvertex = true;
7574                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7575                         break;
7576                 case Q3DEFORM_WAVE:
7577                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7578                                 break; // if wavefunc is a nop, ignore this transform
7579                         if (!dynamicvertex)
7580                         {
7581                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7582                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7583                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7584                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7585                         }
7586                         dynamicvertex = true;
7587                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7588                         break;
7589                 case Q3DEFORM_BULGE:
7590                         if (!dynamicvertex)
7591                         {
7592                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7593                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7594                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7595                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7596                         }
7597                         dynamicvertex = true;
7598                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7599                         break;
7600                 case Q3DEFORM_MOVE:
7601                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7602                                 break; // if wavefunc is a nop, ignore this transform
7603                         if (!dynamicvertex)
7604                         {
7605                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7606                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7607                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7608                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7609                         }
7610                         dynamicvertex = true;
7611                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7612                         break;
7613                 }
7614         }
7615         if (rsurface.texture->materialshaderpass)
7616         {
7617                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7618                 {
7619                 default:
7620                 case Q3TCGEN_TEXTURE:
7621                         break;
7622                 case Q3TCGEN_LIGHTMAP:
7623                         if (!dynamicvertex)
7624                         {
7625                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7626                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7627                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7628                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7629                         }
7630                         dynamicvertex = true;
7631                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7632                         break;
7633                 case Q3TCGEN_VECTOR:
7634                         if (!dynamicvertex)
7635                         {
7636                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7637                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7638                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7639                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7640                         }
7641                         dynamicvertex = true;
7642                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7643                         break;
7644                 case Q3TCGEN_ENVIRONMENT:
7645                         if (!dynamicvertex)
7646                         {
7647                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7648                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7649                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7650                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7651                         }
7652                         dynamicvertex = true;
7653                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7654                         break;
7655                 }
7656                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7657                 {
7658                         if (!dynamicvertex)
7659                         {
7660                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7661                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7662                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7663                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7664                         }
7665                         dynamicvertex = true;
7666                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7667                 }
7668         }
7669
7670         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7671         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7672         // we ensure this by treating the vertex batch as dynamic...
7673         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7674         {
7675                 if (!dynamicvertex)
7676                 {
7677                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7678                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7679                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7680                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7681                 }
7682                 dynamicvertex = true;
7683         }
7684
7685         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7686         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7687                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7688
7689         rsurface.batchvertex3f = rsurface.modelvertex3f;
7690         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7691         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7692         rsurface.batchsvector3f = rsurface.modelsvector3f;
7693         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7694         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7695         rsurface.batchtvector3f = rsurface.modeltvector3f;
7696         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7697         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7698         rsurface.batchnormal3f = rsurface.modelnormal3f;
7699         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7700         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7701         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7702         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7703         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7704         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7705         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7706         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7707         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7708         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7709         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7710         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7711         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7712         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7713         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7714         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7715         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7716         rsurface.batchelement3i = rsurface.modelelement3i;
7717         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7718         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7719         rsurface.batchelement3s = rsurface.modelelement3s;
7720         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7721         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7722         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7723         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7724         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7725         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7726         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7727
7728         // if any dynamic vertex processing has to occur in software, we copy the
7729         // entire surface list together before processing to rebase the vertices
7730         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7731         //
7732         // if any gaps exist and we do not have a static vertex buffer, we have to
7733         // copy the surface list together to avoid wasting upload bandwidth on the
7734         // vertices in the gaps.
7735         //
7736         // if gaps exist and we have a static vertex buffer, we can choose whether
7737         // to combine the index buffer ranges into one dynamic index buffer or
7738         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7739         //
7740         // in many cases the batch is reduced to one draw call.
7741
7742         rsurface.batchmultidraw = false;
7743         rsurface.batchmultidrawnumsurfaces = 0;
7744         rsurface.batchmultidrawsurfacelist = NULL;
7745
7746         if (!dynamicvertex)
7747         {
7748                 // static vertex data, just set pointers...
7749                 rsurface.batchgeneratedvertex = false;
7750                 // if there are gaps, we want to build a combined index buffer,
7751                 // otherwise use the original static buffer with an appropriate offset
7752                 if (gaps)
7753                 {
7754                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7755                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7756                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7757                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7758                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7759                         {
7760                                 rsurface.batchmultidraw = true;
7761                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7762                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7763                                 return;
7764                         }
7765                         // build a new triangle elements array for this batch
7766                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7767                         rsurface.batchfirsttriangle = 0;
7768                         numtriangles = 0;
7769                         for (i = 0;i < texturenumsurfaces;i++)
7770                         {
7771                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7772                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7773                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7774                                 numtriangles += surfacenumtriangles;
7775                         }
7776                         rsurface.batchelement3i_indexbuffer = NULL;
7777                         rsurface.batchelement3i_bufferoffset = 0;
7778                         rsurface.batchelement3s = NULL;
7779                         rsurface.batchelement3s_indexbuffer = NULL;
7780                         rsurface.batchelement3s_bufferoffset = 0;
7781                         if (endvertex <= 65536)
7782                         {
7783                                 // make a 16bit (unsigned short) index array if possible
7784                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7785                                 for (i = 0;i < numtriangles*3;i++)
7786                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7787                         }
7788                 }
7789                 else
7790                 {
7791                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7792                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7793                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7794                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7795                 }
7796                 return;
7797         }
7798
7799         // something needs software processing, do it for real...
7800         // we only directly handle separate array data in this case and then
7801         // generate interleaved data if needed...
7802         rsurface.batchgeneratedvertex = true;
7803         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7804         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7805         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7806         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7807
7808         // now copy the vertex data into a combined array and make an index array
7809         // (this is what Quake3 does all the time)
7810         // we also apply any skeletal animation here that would have been done in
7811         // the vertex shader, because most of the dynamic vertex animation cases
7812         // need actual vertex positions and normals
7813         //if (dynamicvertex)
7814         {
7815                 rsurface.batchvertex3f = NULL;
7816                 rsurface.batchvertex3f_vertexbuffer = NULL;
7817                 rsurface.batchvertex3f_bufferoffset = 0;
7818                 rsurface.batchsvector3f = NULL;
7819                 rsurface.batchsvector3f_vertexbuffer = NULL;
7820                 rsurface.batchsvector3f_bufferoffset = 0;
7821                 rsurface.batchtvector3f = NULL;
7822                 rsurface.batchtvector3f_vertexbuffer = NULL;
7823                 rsurface.batchtvector3f_bufferoffset = 0;
7824                 rsurface.batchnormal3f = NULL;
7825                 rsurface.batchnormal3f_vertexbuffer = NULL;
7826                 rsurface.batchnormal3f_bufferoffset = 0;
7827                 rsurface.batchlightmapcolor4f = NULL;
7828                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7829                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7830                 rsurface.batchtexcoordtexture2f = NULL;
7831                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7832                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7833                 rsurface.batchtexcoordlightmap2f = NULL;
7834                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7835                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7836                 rsurface.batchskeletalindex4ub = NULL;
7837                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7838                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7839                 rsurface.batchskeletalweight4ub = NULL;
7840                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7841                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7842                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7843                 rsurface.batchelement3i_indexbuffer = NULL;
7844                 rsurface.batchelement3i_bufferoffset = 0;
7845                 rsurface.batchelement3s = NULL;
7846                 rsurface.batchelement3s_indexbuffer = NULL;
7847                 rsurface.batchelement3s_bufferoffset = 0;
7848                 rsurface.batchskeletaltransform3x4buffer = NULL;
7849                 rsurface.batchskeletaltransform3x4offset = 0;
7850                 rsurface.batchskeletaltransform3x4size = 0;
7851                 // we'll only be setting up certain arrays as needed
7852                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7853                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7854                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7855                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7856                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7857                 {
7858                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7859                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7860                 }
7861                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7862                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7863                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7864                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7865                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7866                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7867                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7868                 {
7869                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7870                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7871                 }
7872                 numvertices = 0;
7873                 numtriangles = 0;
7874                 for (i = 0;i < texturenumsurfaces;i++)
7875                 {
7876                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7877                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7878                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7879                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7880                         // copy only the data requested
7881                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7882                         {
7883                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7884                                 {
7885                                         if (rsurface.batchvertex3f)
7886                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7887                                         else
7888                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7889                                 }
7890                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7891                                 {
7892                                         if (rsurface.modelnormal3f)
7893                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7894                                         else
7895                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7896                                 }
7897                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7898                                 {
7899                                         if (rsurface.modelsvector3f)
7900                                         {
7901                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7902                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7903                                         }
7904                                         else
7905                                         {
7906                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7907                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7908                                         }
7909                                 }
7910                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7911                                 {
7912                                         if (rsurface.modellightmapcolor4f)
7913                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7914                                         else
7915                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7916                                 }
7917                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7918                                 {
7919                                         if (rsurface.modeltexcoordtexture2f)
7920                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7921                                         else
7922                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7923                                 }
7924                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7925                                 {
7926                                         if (rsurface.modeltexcoordlightmap2f)
7927                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7928                                         else
7929                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7930                                 }
7931                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7932                                 {
7933                                         if (rsurface.modelskeletalindex4ub)
7934                                         {
7935                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7936                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7937                                         }
7938                                         else
7939                                         {
7940                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7941                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7942                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7943                                                 for (j = 0;j < surfacenumvertices;j++)
7944                                                         ub[j*4] = 255;
7945                                         }
7946                                 }
7947                         }
7948                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7949                         numvertices += surfacenumvertices;
7950                         numtriangles += surfacenumtriangles;
7951                 }
7952
7953                 // generate a 16bit index array as well if possible
7954                 // (in general, dynamic batches fit)
7955                 if (numvertices <= 65536)
7956                 {
7957                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7958                         for (i = 0;i < numtriangles*3;i++)
7959                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7960                 }
7961
7962                 // since we've copied everything, the batch now starts at 0
7963                 rsurface.batchfirstvertex = 0;
7964                 rsurface.batchnumvertices = batchnumvertices;
7965                 rsurface.batchfirsttriangle = 0;
7966                 rsurface.batchnumtriangles = batchnumtriangles;
7967         }
7968
7969         // apply skeletal animation that would have been done in the vertex shader
7970         if (rsurface.batchskeletaltransform3x4)
7971         {
7972                 const unsigned char *si;
7973                 const unsigned char *sw;
7974                 const float *t[4];
7975                 const float *b = rsurface.batchskeletaltransform3x4;
7976                 float *vp, *vs, *vt, *vn;
7977                 float w[4];
7978                 float m[3][4], n[3][4];
7979                 float tp[3], ts[3], tt[3], tn[3];
7980                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7981                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7982                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7983                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7984                 si = rsurface.batchskeletalindex4ub;
7985                 sw = rsurface.batchskeletalweight4ub;
7986                 vp = rsurface.batchvertex3f;
7987                 vs = rsurface.batchsvector3f;
7988                 vt = rsurface.batchtvector3f;
7989                 vn = rsurface.batchnormal3f;
7990                 memset(m[0], 0, sizeof(m));
7991                 memset(n[0], 0, sizeof(n));
7992                 for (i = 0;i < batchnumvertices;i++)
7993                 {
7994                         t[0] = b + si[0]*12;
7995                         if (sw[0] == 255)
7996                         {
7997                                 // common case - only one matrix
7998                                 m[0][0] = t[0][ 0];
7999                                 m[0][1] = t[0][ 1];
8000                                 m[0][2] = t[0][ 2];
8001                                 m[0][3] = t[0][ 3];
8002                                 m[1][0] = t[0][ 4];
8003                                 m[1][1] = t[0][ 5];
8004                                 m[1][2] = t[0][ 6];
8005                                 m[1][3] = t[0][ 7];
8006                                 m[2][0] = t[0][ 8];
8007                                 m[2][1] = t[0][ 9];
8008                                 m[2][2] = t[0][10];
8009                                 m[2][3] = t[0][11];
8010                         }
8011                         else if (sw[2] + sw[3])
8012                         {
8013                                 // blend 4 matrices
8014                                 t[1] = b + si[1]*12;
8015                                 t[2] = b + si[2]*12;
8016                                 t[3] = b + si[3]*12;
8017                                 w[0] = sw[0] * (1.0f / 255.0f);
8018                                 w[1] = sw[1] * (1.0f / 255.0f);
8019                                 w[2] = sw[2] * (1.0f / 255.0f);
8020                                 w[3] = sw[3] * (1.0f / 255.0f);
8021                                 // blend the matrices
8022                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8023                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8024                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8025                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8026                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8027                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8028                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8029                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8030                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8031                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8032                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8033                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8034                         }
8035                         else
8036                         {
8037                                 // blend 2 matrices
8038                                 t[1] = b + si[1]*12;
8039                                 w[0] = sw[0] * (1.0f / 255.0f);
8040                                 w[1] = sw[1] * (1.0f / 255.0f);
8041                                 // blend the matrices
8042                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8043                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8044                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8045                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8046                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8047                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8048                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8049                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8050                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8051                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8052                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8053                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8054                         }
8055                         si += 4;
8056                         sw += 4;
8057                         // modify the vertex
8058                         VectorCopy(vp, tp);
8059                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8060                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8061                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8062                         vp += 3;
8063                         if (vn)
8064                         {
8065                                 // the normal transformation matrix is a set of cross products...
8066                                 CrossProduct(m[1], m[2], n[0]);
8067                                 CrossProduct(m[2], m[0], n[1]);
8068                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8069                                 VectorCopy(vn, tn);
8070                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8071                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8072                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8073                                 VectorNormalize(vn);
8074                                 vn += 3;
8075                                 if (vs)
8076                                 {
8077                                         VectorCopy(vs, ts);
8078                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8079                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8080                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8081                                         VectorNormalize(vs);
8082                                         vs += 3;
8083                                         VectorCopy(vt, tt);
8084                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8085                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8086                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8087                                         VectorNormalize(vt);
8088                                         vt += 3;
8089                                 }
8090                         }
8091                 }
8092                 rsurface.batchskeletaltransform3x4 = NULL;
8093                 rsurface.batchskeletalnumtransforms = 0;
8094         }
8095
8096         // q1bsp surfaces rendered in vertex color mode have to have colors
8097         // calculated based on lightstyles
8098         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8099         {
8100                 // generate color arrays for the surfaces in this list
8101                 int c[4];
8102                 int scale;
8103                 int size3;
8104                 const int *offsets;
8105                 const unsigned char *lm;
8106                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8107                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8108                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8109                 numvertices = 0;
8110                 for (i = 0;i < texturenumsurfaces;i++)
8111                 {
8112                         surface = texturesurfacelist[i];
8113                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8114                         surfacenumvertices = surface->num_vertices;
8115                         if (surface->lightmapinfo->samples)
8116                         {
8117                                 for (j = 0;j < surfacenumvertices;j++)
8118                                 {
8119                                         lm = surface->lightmapinfo->samples + offsets[j];
8120                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8121                                         VectorScale(lm, scale, c);
8122                                         if (surface->lightmapinfo->styles[1] != 255)
8123                                         {
8124                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8125                                                 lm += size3;
8126                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8127                                                 VectorMA(c, scale, lm, c);
8128                                                 if (surface->lightmapinfo->styles[2] != 255)
8129                                                 {
8130                                                         lm += size3;
8131                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8132                                                         VectorMA(c, scale, lm, c);
8133                                                         if (surface->lightmapinfo->styles[3] != 255)
8134                                                         {
8135                                                                 lm += size3;
8136                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8137                                                                 VectorMA(c, scale, lm, c);
8138                                                         }
8139                                                 }
8140                                         }
8141                                         c[0] >>= 7;
8142                                         c[1] >>= 7;
8143                                         c[2] >>= 7;
8144                                         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);
8145                                         numvertices++;
8146                                 }
8147                         }
8148                         else
8149                         {
8150                                 for (j = 0;j < surfacenumvertices;j++)
8151                                 {
8152                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8153                                         numvertices++;
8154                                 }
8155                         }
8156                 }
8157         }
8158
8159         // if vertices are deformed (sprite flares and things in maps, possibly
8160         // water waves, bulges and other deformations), modify the copied vertices
8161         // in place
8162         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8163         {
8164                 float scale;
8165                 switch (deform->deform)
8166                 {
8167                 default:
8168                 case Q3DEFORM_PROJECTIONSHADOW:
8169                 case Q3DEFORM_TEXT0:
8170                 case Q3DEFORM_TEXT1:
8171                 case Q3DEFORM_TEXT2:
8172                 case Q3DEFORM_TEXT3:
8173                 case Q3DEFORM_TEXT4:
8174                 case Q3DEFORM_TEXT5:
8175                 case Q3DEFORM_TEXT6:
8176                 case Q3DEFORM_TEXT7:
8177                 case Q3DEFORM_NONE:
8178                         break;
8179                 case Q3DEFORM_AUTOSPRITE:
8180                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8181                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8182                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8183                         VectorNormalize(newforward);
8184                         VectorNormalize(newright);
8185                         VectorNormalize(newup);
8186 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8187 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8188 //                      rsurface.batchvertex3f_bufferoffset = 0;
8189 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8190 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8191 //                      rsurface.batchsvector3f_bufferoffset = 0;
8192 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8193 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8194 //                      rsurface.batchtvector3f_bufferoffset = 0;
8195 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8196 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8197 //                      rsurface.batchnormal3f_bufferoffset = 0;
8198                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8199                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8200                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8201                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8202                                 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);
8203                         // a single autosprite surface can contain multiple sprites...
8204                         for (j = 0;j < batchnumvertices - 3;j += 4)
8205                         {
8206                                 VectorClear(center);
8207                                 for (i = 0;i < 4;i++)
8208                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8209                                 VectorScale(center, 0.25f, center);
8210                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8211                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8212                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8213                                 for (i = 0;i < 4;i++)
8214                                 {
8215                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8216                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8217                                 }
8218                         }
8219                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8220                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8221                         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);
8222                         break;
8223                 case Q3DEFORM_AUTOSPRITE2:
8224                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8225                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8226                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8227                         VectorNormalize(newforward);
8228                         VectorNormalize(newright);
8229                         VectorNormalize(newup);
8230 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8231 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8232 //                      rsurface.batchvertex3f_bufferoffset = 0;
8233                         {
8234                                 const float *v1, *v2;
8235                                 vec3_t start, end;
8236                                 float f, l;
8237                                 struct
8238                                 {
8239                                         float length2;
8240                                         const float *v1;
8241                                         const float *v2;
8242                                 }
8243                                 shortest[2];
8244                                 memset(shortest, 0, sizeof(shortest));
8245                                 // a single autosprite surface can contain multiple sprites...
8246                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8247                                 {
8248                                         VectorClear(center);
8249                                         for (i = 0;i < 4;i++)
8250                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8251                                         VectorScale(center, 0.25f, center);
8252                                         // find the two shortest edges, then use them to define the
8253                                         // axis vectors for rotating around the central axis
8254                                         for (i = 0;i < 6;i++)
8255                                         {
8256                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8257                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8258                                                 l = VectorDistance2(v1, v2);
8259                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8260                                                 if (v1[2] != v2[2])
8261                                                         l += (1.0f / 1024.0f);
8262                                                 if (shortest[0].length2 > l || i == 0)
8263                                                 {
8264                                                         shortest[1] = shortest[0];
8265                                                         shortest[0].length2 = l;
8266                                                         shortest[0].v1 = v1;
8267                                                         shortest[0].v2 = v2;
8268                                                 }
8269                                                 else if (shortest[1].length2 > l || i == 1)
8270                                                 {
8271                                                         shortest[1].length2 = l;
8272                                                         shortest[1].v1 = v1;
8273                                                         shortest[1].v2 = v2;
8274                                                 }
8275                                         }
8276                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8277                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8278                                         // this calculates the right vector from the shortest edge
8279                                         // and the up vector from the edge midpoints
8280                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8281                                         VectorNormalize(right);
8282                                         VectorSubtract(end, start, up);
8283                                         VectorNormalize(up);
8284                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8285                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8286                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8287                                         VectorNegate(forward, forward);
8288                                         VectorReflect(forward, 0, up, forward);
8289                                         VectorNormalize(forward);
8290                                         CrossProduct(up, forward, newright);
8291                                         VectorNormalize(newright);
8292                                         // rotate the quad around the up axis vector, this is made
8293                                         // especially easy by the fact we know the quad is flat,
8294                                         // so we only have to subtract the center position and
8295                                         // measure distance along the right vector, and then
8296                                         // multiply that by the newright vector and add back the
8297                                         // center position
8298                                         // we also need to subtract the old position to undo the
8299                                         // displacement from the center, which we do with a
8300                                         // DotProduct, the subtraction/addition of center is also
8301                                         // optimized into DotProducts here
8302                                         l = DotProduct(right, center);
8303                                         for (i = 0;i < 4;i++)
8304                                         {
8305                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8306                                                 f = DotProduct(right, v1) - l;
8307                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8308                                         }
8309                                 }
8310                         }
8311                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8312                         {
8313 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8314 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8315 //                              rsurface.batchnormal3f_bufferoffset = 0;
8316                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8317                         }
8318                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8319                         {
8320 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8321 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8322 //                              rsurface.batchsvector3f_bufferoffset = 0;
8323 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8324 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8325 //                              rsurface.batchtvector3f_bufferoffset = 0;
8326                                 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);
8327                         }
8328                         break;
8329                 case Q3DEFORM_NORMAL:
8330                         // deform the normals to make reflections wavey
8331                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8332                         rsurface.batchnormal3f_vertexbuffer = NULL;
8333                         rsurface.batchnormal3f_bufferoffset = 0;
8334                         for (j = 0;j < batchnumvertices;j++)
8335                         {
8336                                 float vertex[3];
8337                                 float *normal = rsurface.batchnormal3f + 3*j;
8338                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8339                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8340                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8341                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8342                                 VectorNormalize(normal);
8343                         }
8344                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8345                         {
8346 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8347 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8348 //                              rsurface.batchsvector3f_bufferoffset = 0;
8349 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8350 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8351 //                              rsurface.batchtvector3f_bufferoffset = 0;
8352                                 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);
8353                         }
8354                         break;
8355                 case Q3DEFORM_WAVE:
8356                         // deform vertex array to make wavey water and flags and such
8357                         waveparms[0] = deform->waveparms[0];
8358                         waveparms[1] = deform->waveparms[1];
8359                         waveparms[2] = deform->waveparms[2];
8360                         waveparms[3] = deform->waveparms[3];
8361                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8362                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8363                         // this is how a divisor of vertex influence on deformation
8364                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8365                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8366 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8367 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8368 //                      rsurface.batchvertex3f_bufferoffset = 0;
8369 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8370 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8371 //                      rsurface.batchnormal3f_bufferoffset = 0;
8372                         for (j = 0;j < batchnumvertices;j++)
8373                         {
8374                                 // if the wavefunc depends on time, evaluate it per-vertex
8375                                 if (waveparms[3])
8376                                 {
8377                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8378                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8379                                 }
8380                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8381                         }
8382                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8383                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8384                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8385                         {
8386 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8387 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8388 //                              rsurface.batchsvector3f_bufferoffset = 0;
8389 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8390 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8391 //                              rsurface.batchtvector3f_bufferoffset = 0;
8392                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8393                         }
8394                         break;
8395                 case Q3DEFORM_BULGE:
8396                         // deform vertex array to make the surface have moving bulges
8397 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8398 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8399 //                      rsurface.batchvertex3f_bufferoffset = 0;
8400 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8401 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8402 //                      rsurface.batchnormal3f_bufferoffset = 0;
8403                         for (j = 0;j < batchnumvertices;j++)
8404                         {
8405                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8406                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8407                         }
8408                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8409                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8410                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8411                         {
8412 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8413 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8414 //                              rsurface.batchsvector3f_bufferoffset = 0;
8415 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8416 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8417 //                              rsurface.batchtvector3f_bufferoffset = 0;
8418                                 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);
8419                         }
8420                         break;
8421                 case Q3DEFORM_MOVE:
8422                         // deform vertex array
8423                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8424                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8425                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8426                         VectorScale(deform->parms, scale, waveparms);
8427 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8428 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8429 //                      rsurface.batchvertex3f_bufferoffset = 0;
8430                         for (j = 0;j < batchnumvertices;j++)
8431                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8432                         break;
8433                 }
8434         }
8435
8436         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8437         {
8438         // generate texcoords based on the chosen texcoord source
8439                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8440                 {
8441                 default:
8442                 case Q3TCGEN_TEXTURE:
8443                         break;
8444                 case Q3TCGEN_LIGHTMAP:
8445         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8446         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8447         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8448                         if (rsurface.batchtexcoordlightmap2f)
8449                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8450                         break;
8451                 case Q3TCGEN_VECTOR:
8452         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8453         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8454         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8455                         for (j = 0;j < batchnumvertices;j++)
8456                         {
8457                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8458                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8459                         }
8460                         break;
8461                 case Q3TCGEN_ENVIRONMENT:
8462                         // make environment reflections using a spheremap
8463                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8464                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8465                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8466                         for (j = 0;j < batchnumvertices;j++)
8467                         {
8468                                 // identical to Q3A's method, but executed in worldspace so
8469                                 // carried models can be shiny too
8470
8471                                 float viewer[3], d, reflected[3], worldreflected[3];
8472
8473                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8474                                 // VectorNormalize(viewer);
8475
8476                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8477
8478                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8479                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8480                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8481                                 // note: this is proportinal to viewer, so we can normalize later
8482
8483                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8484                                 VectorNormalize(worldreflected);
8485
8486                                 // note: this sphere map only uses world x and z!
8487                                 // so positive and negative y will LOOK THE SAME.
8488                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8489                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8490                         }
8491                         break;
8492                 }
8493                 // the only tcmod that needs software vertex processing is turbulent, so
8494                 // check for it here and apply the changes if needed
8495                 // and we only support that as the first one
8496                 // (handling a mixture of turbulent and other tcmods would be problematic
8497                 //  without punting it entirely to a software path)
8498                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8499                 {
8500                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8501                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8502         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8503         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8504         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8505                         for (j = 0;j < batchnumvertices;j++)
8506                         {
8507                                 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);
8508                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8509                         }
8510                 }
8511         }
8512 }
8513
8514 void RSurf_DrawBatch(void)
8515 {
8516         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8517         // through the pipeline, killing it earlier in the pipeline would have
8518         // per-surface overhead rather than per-batch overhead, so it's best to
8519         // reject it here, before it hits glDraw.
8520         if (rsurface.batchnumtriangles == 0)
8521                 return;
8522 #if 0
8523         // batch debugging code
8524         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8525         {
8526                 int i;
8527                 int j;
8528                 int c;
8529                 const int *e;
8530                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8531                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8532                 {
8533                         c = e[i];
8534                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8535                         {
8536                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8537                                 {
8538                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8539                                                 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);
8540                                         break;
8541                                 }
8542                         }
8543                 }
8544         }
8545 #endif
8546         if (rsurface.batchmultidraw)
8547         {
8548                 // issue multiple draws rather than copying index data
8549                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8550                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8551                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8552                 for (i = 0;i < numsurfaces;)
8553                 {
8554                         // combine consecutive surfaces as one draw
8555                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8556                                 if (surfacelist[j] != surfacelist[k] + 1)
8557                                         break;
8558                         firstvertex = surfacelist[i]->num_firstvertex;
8559                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8560                         firsttriangle = surfacelist[i]->num_firsttriangle;
8561                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8562                         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);
8563                         i = j;
8564                 }
8565         }
8566         else
8567         {
8568                 // there is only one consecutive run of index data (may have been combined)
8569                 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);
8570         }
8571 }
8572
8573 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8574 {
8575         // pick the closest matching water plane
8576         int planeindex, vertexindex, bestplaneindex = -1;
8577         float d, bestd;
8578         vec3_t vert;
8579         const float *v;
8580         r_waterstate_waterplane_t *p;
8581         qbool prepared = false;
8582         bestd = 0;
8583         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8584         {
8585                 if(p->camera_entity != rsurface.texture->camera_entity)
8586                         continue;
8587                 d = 0;
8588                 if(!prepared)
8589                 {
8590                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8591                         prepared = true;
8592                         if(rsurface.batchnumvertices == 0)
8593                                 break;
8594                 }
8595                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8596                 {
8597                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8598                         d += fabs(PlaneDiff(vert, &p->plane));
8599                 }
8600                 if (bestd > d || bestplaneindex < 0)
8601                 {
8602                         bestd = d;
8603                         bestplaneindex = planeindex;
8604                 }
8605         }
8606         return bestplaneindex;
8607         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8608         // this situation though, as it might be better to render single larger
8609         // batches with useless stuff (backface culled for example) than to
8610         // render multiple smaller batches
8611 }
8612
8613 void RSurf_SetupDepthAndCulling(bool ui)
8614 {
8615         // submodels are biased to avoid z-fighting with world surfaces that they
8616         // may be exactly overlapping (avoids z-fighting artifacts on certain
8617         // doors and things in Quake maps)
8618         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8619         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8620         GL_DepthTest(!ui && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8621         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8622 }
8623
8624 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8625 {
8626         int j;
8627         const float *v;
8628         float p[3], mins[3], maxs[3];
8629         int scissor[4];
8630         // transparent sky would be ridiculous
8631         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8632                 return;
8633         R_SetupShader_Generic_NoTexture(false, false);
8634         skyrenderlater = true;
8635         RSurf_SetupDepthAndCulling(false);
8636         GL_DepthMask(true);
8637
8638         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8639         if (r_sky_scissor.integer)
8640         {
8641                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8642                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8643                 {
8644                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8645                         if (j > 0)
8646                         {
8647                                 if (mins[0] > p[0]) mins[0] = p[0];
8648                                 if (mins[1] > p[1]) mins[1] = p[1];
8649                                 if (mins[2] > p[2]) mins[2] = p[2];
8650                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8651                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8652                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8653                         }
8654                         else
8655                         {
8656                                 VectorCopy(p, mins);
8657                                 VectorCopy(p, maxs);
8658                         }
8659                 }
8660                 if (!R_ScissorForBBox(mins, maxs, scissor))
8661                 {
8662                         if (skyscissor[2])
8663                         {
8664                                 if (skyscissor[0] > scissor[0])
8665                                 {
8666                                         skyscissor[2] += skyscissor[0] - scissor[0];
8667                                         skyscissor[0] = scissor[0];
8668                                 }
8669                                 if (skyscissor[1] > scissor[1])
8670                                 {
8671                                         skyscissor[3] += skyscissor[1] - scissor[1];
8672                                         skyscissor[1] = scissor[1];
8673                                 }
8674                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8675                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8676                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8677                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8678                         }
8679                         else
8680                                 Vector4Copy(scissor, skyscissor);
8681                 }
8682         }
8683
8684         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8685         // skymasking on them, and Quake3 never did sky masking (unlike
8686         // software Quake and software Quake2), so disable the sky masking
8687         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8688         // and skymasking also looks very bad when noclipping outside the
8689         // level, so don't use it then either.
8690         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)
8691         {
8692                 R_Mesh_ResetTextureState();
8693                 if (skyrendermasked)
8694                 {
8695                         R_SetupShader_DepthOrShadow(false, false, false);
8696                         // depth-only (masking)
8697                         GL_ColorMask(0, 0, 0, 0);
8698                         // just to make sure that braindead drivers don't draw
8699                         // anything despite that colormask...
8700                         GL_BlendFunc(GL_ZERO, GL_ONE);
8701                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8702                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8703                 }
8704                 else
8705                 {
8706                         R_SetupShader_Generic_NoTexture(false, false);
8707                         // fog sky
8708                         GL_BlendFunc(GL_ONE, GL_ZERO);
8709                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8710                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8711                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8712                 }
8713                 RSurf_DrawBatch();
8714                 if (skyrendermasked)
8715                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8716         }
8717         R_Mesh_ResetTextureState();
8718         GL_Color(1, 1, 1, 1);
8719 }
8720
8721 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8722 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8723 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8724 {
8725         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8726                 return;
8727         if (prepass)
8728         {
8729                 // render screenspace normalmap to texture
8730                 GL_DepthMask(true);
8731                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8732                 RSurf_DrawBatch();
8733                 return;
8734         }
8735
8736         // bind lightmap texture
8737
8738         // water/refraction/reflection/camera surfaces have to be handled specially
8739         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8740         {
8741                 int start, end, startplaneindex;
8742                 for (start = 0;start < texturenumsurfaces;start = end)
8743                 {
8744                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8745                         if(startplaneindex < 0)
8746                         {
8747                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8748                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8749                                 end = start + 1;
8750                                 continue;
8751                         }
8752                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8753                                 ;
8754                         // now that we have a batch using the same planeindex, render it
8755                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8756                         {
8757                                 // render water or distortion background
8758                                 GL_DepthMask(true);
8759                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8760                                 RSurf_DrawBatch();
8761                                 // blend surface on top
8762                                 GL_DepthMask(false);
8763                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8764                                 RSurf_DrawBatch();
8765                         }
8766                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8767                         {
8768                                 // render surface with reflection texture as input
8769                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8770                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8771                                 RSurf_DrawBatch();
8772                         }
8773                 }
8774                 return;
8775         }
8776
8777         // render surface batch normally
8778         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8779         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8780         RSurf_DrawBatch();
8781 }
8782
8783 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8784 {
8785         int vi;
8786         int j;
8787         int texturesurfaceindex;
8788         int k;
8789         const msurface_t *surface;
8790         float surfacecolor4f[4];
8791         float c[4];
8792         texture_t *t = rsurface.texture;
8793
8794 //      R_Mesh_ResetTextureState();
8795         R_SetupShader_Generic_NoTexture(false, false);
8796
8797         GL_BlendFunc(GL_ONE, GL_ZERO);
8798         GL_DepthMask(writedepth);
8799
8800         switch (r_showsurfaces.integer)
8801         {
8802                 case 1:
8803                 default:
8804                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8805                         vi = 0;
8806                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8807                         {
8808                                 surface = texturesurfacelist[texturesurfaceindex];
8809                                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8810                                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8811                                 for (j = 0;j < surface->num_vertices;j++)
8812                                 {
8813                                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8814                                         vi++;
8815                                 }
8816                         }
8817                         break;
8818                 case 3:
8819                         if(t && t->currentskinframe)
8820                         {
8821                                 Vector4Copy(t->currentskinframe->avgcolor, c);
8822                                 c[3] *= t->currentalpha;
8823                         }
8824                         else
8825                         {
8826                                 Vector4Set(c, 1, 0, 1, 1);
8827                         }
8828                         if (t && (t->pantstexture || t->shirttexture))
8829                         {
8830                                 VectorMAM(0.7, t->render_colormap_pants, 0.3, t->render_colormap_shirt, c);
8831                         }
8832                         VectorScale(c, 2 * r_refdef.view.colorscale, c);
8833                         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
8834                                 c[3] *= r_wateralpha.value;
8835                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8836                         vi = 0;
8837                         if (rsurface.modellightmapcolor4f)
8838                         {
8839                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8840                                 {
8841                                         surface = texturesurfacelist[texturesurfaceindex];
8842                                         for (j = 0;j < surface->num_vertices;j++)
8843                                         {
8844                                                 float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
8845                                                 Vector4Multiply(ptr, c, ptr);
8846                                                 vi++;
8847                                         }
8848                                 }
8849                         }
8850                         else
8851                         {
8852                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8853                                 {
8854                                         surface = texturesurfacelist[texturesurfaceindex];
8855                                         for (j = 0;j < surface->num_vertices;j++)
8856                                         {
8857                                                 float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
8858                                                 Vector4Copy(c, ptr);
8859                                                 vi++;
8860                                         }
8861                                 }
8862                         }
8863                         break;
8864         }
8865         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8866         RSurf_DrawBatch();
8867 }
8868
8869 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8870 {
8871         CHECKGLERROR
8872         RSurf_SetupDepthAndCulling(ui);
8873         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8874         {
8875                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8876                 return;
8877         }
8878         switch (vid.renderpath)
8879         {
8880         case RENDERPATH_GL32:
8881         case RENDERPATH_GLES2:
8882                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8883                 break;
8884         }
8885         CHECKGLERROR
8886 }
8887
8888 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8889 {
8890         int i, j;
8891         int texturenumsurfaces, endsurface;
8892         texture_t *texture;
8893         const msurface_t *surface;
8894         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8895
8896         RSurf_ActiveModelEntity(ent, true, true, false);
8897
8898         if (r_transparentdepthmasking.integer)
8899         {
8900                 qbool setup = false;
8901                 for (i = 0;i < numsurfaces;i = j)
8902                 {
8903                         j = i + 1;
8904                         surface = rsurface.modelsurfaces + surfacelist[i];
8905                         texture = surface->texture;
8906                         rsurface.texture = R_GetCurrentTexture(texture);
8907                         rsurface.lightmaptexture = NULL;
8908                         rsurface.deluxemaptexture = NULL;
8909                         rsurface.uselightmaptexture = false;
8910                         // scan ahead until we find a different texture
8911                         endsurface = min(i + 1024, numsurfaces);
8912                         texturenumsurfaces = 0;
8913                         texturesurfacelist[texturenumsurfaces++] = surface;
8914                         for (;j < endsurface;j++)
8915                         {
8916                                 surface = rsurface.modelsurfaces + surfacelist[j];
8917                                 if (texture != surface->texture)
8918                                         break;
8919                                 texturesurfacelist[texturenumsurfaces++] = surface;
8920                         }
8921                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8922                                 continue;
8923                         // render the range of surfaces as depth
8924                         if (!setup)
8925                         {
8926                                 setup = true;
8927                                 GL_ColorMask(0,0,0,0);
8928                                 GL_Color(1,1,1,1);
8929                                 GL_DepthTest(true);
8930                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8931                                 GL_DepthMask(true);
8932 //                              R_Mesh_ResetTextureState();
8933                         }
8934                         RSurf_SetupDepthAndCulling(false);
8935                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8936                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8937                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8938                         RSurf_DrawBatch();
8939                 }
8940                 if (setup)
8941                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8942         }
8943
8944         for (i = 0;i < numsurfaces;i = j)
8945         {
8946                 j = i + 1;
8947                 surface = rsurface.modelsurfaces + surfacelist[i];
8948                 texture = surface->texture;
8949                 rsurface.texture = R_GetCurrentTexture(texture);
8950                 // scan ahead until we find a different texture
8951                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8952                 texturenumsurfaces = 0;
8953                 texturesurfacelist[texturenumsurfaces++] = surface;
8954                         rsurface.lightmaptexture = surface->lightmaptexture;
8955                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8956                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8957                         for (;j < endsurface;j++)
8958                         {
8959                                 surface = rsurface.modelsurfaces + surfacelist[j];
8960                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8961                                         break;
8962                                 texturesurfacelist[texturenumsurfaces++] = surface;
8963                         }
8964                 // render the range of surfaces
8965                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8966         }
8967         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8968 }
8969
8970 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8971 {
8972         // transparent surfaces get pushed off into the transparent queue
8973         int surfacelistindex;
8974         const msurface_t *surface;
8975         vec3_t tempcenter, center;
8976         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8977         {
8978                 surface = texturesurfacelist[surfacelistindex];
8979                 if (r_transparent_sortsurfacesbynearest.integer)
8980                 {
8981                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8982                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8983                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8984                 }
8985                 else
8986                 {
8987                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8988                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8989                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8990                 }
8991                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8992                 if (rsurface.entity->transparent_offset) // transparent offset
8993                 {
8994                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8995                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8996                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8997                 }
8998                 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);
8999         }
9000 }
9001
9002 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9003 {
9004         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9005                 return;
9006         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9007                 return;
9008         RSurf_SetupDepthAndCulling(false);
9009         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9010         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9011         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9012         RSurf_DrawBatch();
9013 }
9014
9015 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9016 {
9017         CHECKGLERROR
9018         if (ui)
9019                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9020         else if (depthonly)
9021                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9022         else if (prepass)
9023         {
9024                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9025                         return;
9026                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9027                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9028                 else
9029                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9030         }
9031         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9032                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9033         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9034                 return;
9035         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9036         {
9037                 // in the deferred case, transparent surfaces were queued during prepass
9038                 if (!r_shadow_usingdeferredprepass)
9039                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9040         }
9041         else
9042         {
9043                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9044                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9045         }
9046         CHECKGLERROR
9047 }
9048
9049 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9050 {
9051         int i, j;
9052         texture_t *texture;
9053         R_FrameData_SetMark();
9054         // break the surface list down into batches by texture and use of lightmapping
9055         for (i = 0;i < numsurfaces;i = j)
9056         {
9057                 j = i + 1;
9058                 // texture is the base texture pointer, rsurface.texture is the
9059                 // current frame/skin the texture is directing us to use (for example
9060                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9061                 // use skin 1 instead)
9062                 texture = surfacelist[i]->texture;
9063                 rsurface.texture = R_GetCurrentTexture(texture);
9064                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9065                 {
9066                         // if this texture is not the kind we want, skip ahead to the next one
9067                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9068                                 ;
9069                         continue;
9070                 }
9071                 if(depthonly || prepass)
9072                 {
9073                         rsurface.lightmaptexture = NULL;
9074                         rsurface.deluxemaptexture = NULL;
9075                         rsurface.uselightmaptexture = false;
9076                         // simply scan ahead until we find a different texture or lightmap state
9077                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9078                                 ;
9079                 }
9080                 else
9081                 {
9082                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9083                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9084                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9085                         // simply scan ahead until we find a different texture or lightmap state
9086                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9087                                 ;
9088                 }
9089                 // render the range of surfaces
9090                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9091         }
9092         R_FrameData_ReturnToMark();
9093 }
9094
9095 float locboxvertex3f[6*4*3] =
9096 {
9097         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9098         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9099         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9100         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9101         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9102         1,0,0, 0,0,0, 0,1,0, 1,1,0
9103 };
9104
9105 unsigned short locboxelements[6*2*3] =
9106 {
9107          0, 1, 2, 0, 2, 3,
9108          4, 5, 6, 4, 6, 7,
9109          8, 9,10, 8,10,11,
9110         12,13,14, 12,14,15,
9111         16,17,18, 16,18,19,
9112         20,21,22, 20,22,23
9113 };
9114
9115 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9116 {
9117         int i, j;
9118         cl_locnode_t *loc = (cl_locnode_t *)ent;
9119         vec3_t mins, size;
9120         float vertex3f[6*4*3];
9121         CHECKGLERROR
9122         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9123         GL_DepthMask(false);
9124         GL_DepthRange(0, 1);
9125         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9126         GL_DepthTest(true);
9127         GL_CullFace(GL_NONE);
9128         R_EntityMatrix(&identitymatrix);
9129
9130 //      R_Mesh_ResetTextureState();
9131
9132         i = surfacelist[0];
9133         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9134                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9135                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9136                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9137
9138         if (VectorCompare(loc->mins, loc->maxs))
9139         {
9140                 VectorSet(size, 2, 2, 2);
9141                 VectorMA(loc->mins, -0.5f, size, mins);
9142         }
9143         else
9144         {
9145                 VectorCopy(loc->mins, mins);
9146                 VectorSubtract(loc->maxs, loc->mins, size);
9147         }
9148
9149         for (i = 0;i < 6*4*3;)
9150                 for (j = 0;j < 3;j++, i++)
9151                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9152
9153         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9154         R_SetupShader_Generic_NoTexture(false, false);
9155         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9156 }
9157
9158 void R_DrawLocs(void)
9159 {
9160         int index;
9161         cl_locnode_t *loc, *nearestloc;
9162         vec3_t center;
9163         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9164         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9165         {
9166                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9167                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9168         }
9169 }
9170
9171 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9172 {
9173         if (decalsystem->decals)
9174                 Mem_Free(decalsystem->decals);
9175         memset(decalsystem, 0, sizeof(*decalsystem));
9176 }
9177
9178 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)
9179 {
9180         tridecal_t *decal;
9181         tridecal_t *decals;
9182         int i;
9183
9184         // expand or initialize the system
9185         if (decalsystem->maxdecals <= decalsystem->numdecals)
9186         {
9187                 decalsystem_t old = *decalsystem;
9188                 qbool useshortelements;
9189                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9190                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9191                 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)));
9192                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9193                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9194                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9195                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9196                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9197                 if (decalsystem->numdecals)
9198                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9199                 if (old.decals)
9200                         Mem_Free(old.decals);
9201                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9202                         decalsystem->element3i[i] = i;
9203                 if (useshortelements)
9204                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9205                                 decalsystem->element3s[i] = i;
9206         }
9207
9208         // grab a decal and search for another free slot for the next one
9209         decals = decalsystem->decals;
9210         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9211         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9212                 ;
9213         decalsystem->freedecal = i;
9214         if (decalsystem->numdecals <= i)
9215                 decalsystem->numdecals = i + 1;
9216
9217         // initialize the decal
9218         decal->lived = 0;
9219         decal->triangleindex = triangleindex;
9220         decal->surfaceindex = surfaceindex;
9221         decal->decalsequence = decalsequence;
9222         decal->color4f[0][0] = c0[0];
9223         decal->color4f[0][1] = c0[1];
9224         decal->color4f[0][2] = c0[2];
9225         decal->color4f[0][3] = 1;
9226         decal->color4f[1][0] = c1[0];
9227         decal->color4f[1][1] = c1[1];
9228         decal->color4f[1][2] = c1[2];
9229         decal->color4f[1][3] = 1;
9230         decal->color4f[2][0] = c2[0];
9231         decal->color4f[2][1] = c2[1];
9232         decal->color4f[2][2] = c2[2];
9233         decal->color4f[2][3] = 1;
9234         decal->vertex3f[0][0] = v0[0];
9235         decal->vertex3f[0][1] = v0[1];
9236         decal->vertex3f[0][2] = v0[2];
9237         decal->vertex3f[1][0] = v1[0];
9238         decal->vertex3f[1][1] = v1[1];
9239         decal->vertex3f[1][2] = v1[2];
9240         decal->vertex3f[2][0] = v2[0];
9241         decal->vertex3f[2][1] = v2[1];
9242         decal->vertex3f[2][2] = v2[2];
9243         decal->texcoord2f[0][0] = t0[0];
9244         decal->texcoord2f[0][1] = t0[1];
9245         decal->texcoord2f[1][0] = t1[0];
9246         decal->texcoord2f[1][1] = t1[1];
9247         decal->texcoord2f[2][0] = t2[0];
9248         decal->texcoord2f[2][1] = t2[1];
9249         TriangleNormal(v0, v1, v2, decal->plane);
9250         VectorNormalize(decal->plane);
9251         decal->plane[3] = DotProduct(v0, decal->plane);
9252 }
9253
9254 extern cvar_t cl_decals_bias;
9255 extern cvar_t cl_decals_models;
9256 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9257 // baseparms, parms, temps
9258 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)
9259 {
9260         int cornerindex;
9261         int index;
9262         float v[9][3];
9263         const float *vertex3f;
9264         const float *normal3f;
9265         int numpoints;
9266         float points[2][9][3];
9267         float temp[3];
9268         float tc[9][2];
9269         float f;
9270         float c[9][4];
9271         const int *e;
9272
9273         e = rsurface.modelelement3i + 3*triangleindex;
9274
9275         vertex3f = rsurface.modelvertex3f;
9276         normal3f = rsurface.modelnormal3f;
9277
9278         if (normal3f)
9279         {
9280                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9281                 {
9282                         index = 3*e[cornerindex];
9283                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9284                 }
9285         }
9286         else
9287         {
9288                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9289                 {
9290                         index = 3*e[cornerindex];
9291                         VectorCopy(vertex3f + index, v[cornerindex]);
9292                 }
9293         }
9294
9295         // cull backfaces
9296         //TriangleNormal(v[0], v[1], v[2], normal);
9297         //if (DotProduct(normal, localnormal) < 0.0f)
9298         //      continue;
9299         // clip by each of the box planes formed from the projection matrix
9300         // if anything survives, we emit the decal
9301         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]);
9302         if (numpoints < 3)
9303                 return;
9304         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]);
9305         if (numpoints < 3)
9306                 return;
9307         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]);
9308         if (numpoints < 3)
9309                 return;
9310         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]);
9311         if (numpoints < 3)
9312                 return;
9313         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]);
9314         if (numpoints < 3)
9315                 return;
9316         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]);
9317         if (numpoints < 3)
9318                 return;
9319         // some part of the triangle survived, so we have to accept it...
9320         if (dynamic)
9321         {
9322                 // dynamic always uses the original triangle
9323                 numpoints = 3;
9324                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9325                 {
9326                         index = 3*e[cornerindex];
9327                         VectorCopy(vertex3f + index, v[cornerindex]);
9328                 }
9329         }
9330         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9331         {
9332                 // convert vertex positions to texcoords
9333                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9334                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9335                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9336                 // calculate distance fade from the projection origin
9337                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9338                 f = bound(0.0f, f, 1.0f);
9339                 c[cornerindex][0] = r * f;
9340                 c[cornerindex][1] = g * f;
9341                 c[cornerindex][2] = b * f;
9342                 c[cornerindex][3] = 1.0f;
9343                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9344         }
9345         if (dynamic)
9346                 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);
9347         else
9348                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9349                         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);
9350 }
9351 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)
9352 {
9353         matrix4x4_t projection;
9354         decalsystem_t *decalsystem;
9355         qbool dynamic;
9356         model_t *model;
9357         const msurface_t *surface;
9358         const msurface_t *surfaces;
9359         const texture_t *texture;
9360         int numtriangles;
9361         int surfaceindex;
9362         int triangleindex;
9363         float localorigin[3];
9364         float localnormal[3];
9365         float localmins[3];
9366         float localmaxs[3];
9367         float localsize;
9368         //float normal[3];
9369         float planes[6][4];
9370         float angles[3];
9371         bih_t *bih;
9372         int bih_triangles_count;
9373         int bih_triangles[256];
9374         int bih_surfaces[256];
9375
9376         decalsystem = &ent->decalsystem;
9377         model = ent->model;
9378         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9379         {
9380                 R_DecalSystem_Reset(&ent->decalsystem);
9381                 return;
9382         }
9383
9384         if (!model->brush.data_leafs && !cl_decals_models.integer)
9385         {
9386                 if (decalsystem->model)
9387                         R_DecalSystem_Reset(decalsystem);
9388                 return;
9389         }
9390
9391         if (decalsystem->model != model)
9392                 R_DecalSystem_Reset(decalsystem);
9393         decalsystem->model = model;
9394
9395         RSurf_ActiveModelEntity(ent, true, false, false);
9396
9397         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9398         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9399         VectorNormalize(localnormal);
9400         localsize = worldsize*rsurface.inversematrixscale;
9401         localmins[0] = localorigin[0] - localsize;
9402         localmins[1] = localorigin[1] - localsize;
9403         localmins[2] = localorigin[2] - localsize;
9404         localmaxs[0] = localorigin[0] + localsize;
9405         localmaxs[1] = localorigin[1] + localsize;
9406         localmaxs[2] = localorigin[2] + localsize;
9407
9408         //VectorCopy(localnormal, planes[4]);
9409         //VectorVectors(planes[4], planes[2], planes[0]);
9410         AnglesFromVectors(angles, localnormal, NULL, false);
9411         AngleVectors(angles, planes[0], planes[2], planes[4]);
9412         VectorNegate(planes[0], planes[1]);
9413         VectorNegate(planes[2], planes[3]);
9414         VectorNegate(planes[4], planes[5]);
9415         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9416         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9417         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9418         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9419         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9420         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9421
9422 #if 1
9423 // works
9424 {
9425         matrix4x4_t forwardprojection;
9426         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9427         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9428 }
9429 #else
9430 // broken
9431 {
9432         float projectionvector[4][3];
9433         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9434         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9435         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9436         projectionvector[0][0] = planes[0][0] * ilocalsize;
9437         projectionvector[0][1] = planes[1][0] * ilocalsize;
9438         projectionvector[0][2] = planes[2][0] * ilocalsize;
9439         projectionvector[1][0] = planes[0][1] * ilocalsize;
9440         projectionvector[1][1] = planes[1][1] * ilocalsize;
9441         projectionvector[1][2] = planes[2][1] * ilocalsize;
9442         projectionvector[2][0] = planes[0][2] * ilocalsize;
9443         projectionvector[2][1] = planes[1][2] * ilocalsize;
9444         projectionvector[2][2] = planes[2][2] * ilocalsize;
9445         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9446         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9447         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9448         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9449 }
9450 #endif
9451
9452         dynamic = model->surfmesh.isanimated;
9453         surfaces = model->data_surfaces;
9454
9455         bih = NULL;
9456         bih_triangles_count = -1;
9457         if(!dynamic)
9458         {
9459                 if(model->render_bih.numleafs)
9460                         bih = &model->render_bih;
9461                 else if(model->collision_bih.numleafs)
9462                         bih = &model->collision_bih;
9463         }
9464         if(bih)
9465                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9466         if(bih_triangles_count == 0)
9467                 return;
9468         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9469                 return;
9470         if(bih_triangles_count > 0)
9471         {
9472                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9473                 {
9474                         surfaceindex = bih_surfaces[triangleindex];
9475                         surface = surfaces + surfaceindex;
9476                         texture = surface->texture;
9477                         if (!texture)
9478                                 continue;
9479                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9480                                 continue;
9481                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9482                                 continue;
9483                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9484                 }
9485         }
9486         else
9487         {
9488                 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
9489                 {
9490                         surface = surfaces + surfaceindex;
9491                         // check cull box first because it rejects more than any other check
9492                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9493                                 continue;
9494                         // skip transparent surfaces
9495                         texture = surface->texture;
9496                         if (!texture)
9497                                 continue;
9498                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9499                                 continue;
9500                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9501                                 continue;
9502                         numtriangles = surface->num_triangles;
9503                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9504                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9505                 }
9506         }
9507 }
9508
9509 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9510 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)
9511 {
9512         int renderentityindex;
9513         float worldmins[3];
9514         float worldmaxs[3];
9515         entity_render_t *ent;
9516
9517         worldmins[0] = worldorigin[0] - worldsize;
9518         worldmins[1] = worldorigin[1] - worldsize;
9519         worldmins[2] = worldorigin[2] - worldsize;
9520         worldmaxs[0] = worldorigin[0] + worldsize;
9521         worldmaxs[1] = worldorigin[1] + worldsize;
9522         worldmaxs[2] = worldorigin[2] + worldsize;
9523
9524         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9525
9526         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9527         {
9528                 ent = r_refdef.scene.entities[renderentityindex];
9529                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9530                         continue;
9531
9532                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9533         }
9534 }
9535
9536 typedef struct r_decalsystem_splatqueue_s
9537 {
9538         vec3_t worldorigin;
9539         vec3_t worldnormal;
9540         float color[4];
9541         float tcrange[4];
9542         float worldsize;
9543         unsigned int decalsequence;
9544 }
9545 r_decalsystem_splatqueue_t;
9546
9547 int r_decalsystem_numqueued = 0;
9548 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9549
9550 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)
9551 {
9552         r_decalsystem_splatqueue_t *queue;
9553
9554         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9555                 return;
9556
9557         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9558         VectorCopy(worldorigin, queue->worldorigin);
9559         VectorCopy(worldnormal, queue->worldnormal);
9560         Vector4Set(queue->color, r, g, b, a);
9561         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9562         queue->worldsize = worldsize;
9563         queue->decalsequence = cl.decalsequence++;
9564 }
9565
9566 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9567 {
9568         int i;
9569         r_decalsystem_splatqueue_t *queue;
9570
9571         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9572                 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);
9573         r_decalsystem_numqueued = 0;
9574 }
9575
9576 extern cvar_t cl_decals_max;
9577 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9578 {
9579         int i;
9580         decalsystem_t *decalsystem = &ent->decalsystem;
9581         int numdecals;
9582         unsigned int killsequence;
9583         tridecal_t *decal;
9584         float frametime;
9585         float lifetime;
9586
9587         if (!decalsystem->numdecals)
9588                 return;
9589
9590         if (r_showsurfaces.integer)
9591                 return;
9592
9593         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9594         {
9595                 R_DecalSystem_Reset(decalsystem);
9596                 return;
9597         }
9598
9599         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9600         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9601
9602         if (decalsystem->lastupdatetime)
9603                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9604         else
9605                 frametime = 0;
9606         decalsystem->lastupdatetime = r_refdef.scene.time;
9607         numdecals = decalsystem->numdecals;
9608
9609         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9610         {
9611                 if (decal->color4f[0][3])
9612                 {
9613                         decal->lived += frametime;
9614                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9615                         {
9616                                 memset(decal, 0, sizeof(*decal));
9617                                 if (decalsystem->freedecal > i)
9618                                         decalsystem->freedecal = i;
9619                         }
9620                 }
9621         }
9622         decal = decalsystem->decals;
9623         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9624                 numdecals--;
9625
9626         // collapse the array by shuffling the tail decals into the gaps
9627         for (;;)
9628         {
9629                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9630                         decalsystem->freedecal++;
9631                 if (decalsystem->freedecal == numdecals)
9632                         break;
9633                 decal[decalsystem->freedecal] = decal[--numdecals];
9634         }
9635
9636         decalsystem->numdecals = numdecals;
9637
9638         if (numdecals <= 0)
9639         {
9640                 // if there are no decals left, reset decalsystem
9641                 R_DecalSystem_Reset(decalsystem);
9642         }
9643 }
9644
9645 extern skinframe_t *decalskinframe;
9646 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9647 {
9648         int i;
9649         decalsystem_t *decalsystem = &ent->decalsystem;
9650         int numdecals;
9651         tridecal_t *decal;
9652         float faderate;
9653         float alpha;
9654         float *v3f;
9655         float *c4f;
9656         float *t2f;
9657         const int *e;
9658         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9659         int numtris = 0;
9660
9661         numdecals = decalsystem->numdecals;
9662         if (!numdecals)
9663                 return;
9664
9665         if (r_showsurfaces.integer)
9666                 return;
9667
9668         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9669         {
9670                 R_DecalSystem_Reset(decalsystem);
9671                 return;
9672         }
9673
9674         // if the model is static it doesn't matter what value we give for
9675         // wantnormals and wanttangents, so this logic uses only rules applicable
9676         // to a model, knowing that they are meaningless otherwise
9677         RSurf_ActiveModelEntity(ent, false, false, false);
9678
9679         decalsystem->lastupdatetime = r_refdef.scene.time;
9680
9681         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9682
9683         // update vertex positions for animated models
9684         v3f = decalsystem->vertex3f;
9685         c4f = decalsystem->color4f;
9686         t2f = decalsystem->texcoord2f;
9687         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9688         {
9689                 if (!decal->color4f[0][3])
9690                         continue;
9691
9692                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9693                         continue;
9694
9695                 // skip backfaces
9696                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9697                         continue;
9698
9699                 // update color values for fading decals
9700                 if (decal->lived >= cl_decals_time.value)
9701                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9702                 else
9703                         alpha = 1.0f;
9704
9705                 c4f[ 0] = decal->color4f[0][0] * alpha;
9706                 c4f[ 1] = decal->color4f[0][1] * alpha;
9707                 c4f[ 2] = decal->color4f[0][2] * alpha;
9708                 c4f[ 3] = 1;
9709                 c4f[ 4] = decal->color4f[1][0] * alpha;
9710                 c4f[ 5] = decal->color4f[1][1] * alpha;
9711                 c4f[ 6] = decal->color4f[1][2] * alpha;
9712                 c4f[ 7] = 1;
9713                 c4f[ 8] = decal->color4f[2][0] * alpha;
9714                 c4f[ 9] = decal->color4f[2][1] * alpha;
9715                 c4f[10] = decal->color4f[2][2] * alpha;
9716                 c4f[11] = 1;
9717
9718                 t2f[0] = decal->texcoord2f[0][0];
9719                 t2f[1] = decal->texcoord2f[0][1];
9720                 t2f[2] = decal->texcoord2f[1][0];
9721                 t2f[3] = decal->texcoord2f[1][1];
9722                 t2f[4] = decal->texcoord2f[2][0];
9723                 t2f[5] = decal->texcoord2f[2][1];
9724
9725                 // update vertex positions for animated models
9726                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9727                 {
9728                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9729                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9730                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9731                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9732                 }
9733                 else
9734                 {
9735                         VectorCopy(decal->vertex3f[0], v3f);
9736                         VectorCopy(decal->vertex3f[1], v3f + 3);
9737                         VectorCopy(decal->vertex3f[2], v3f + 6);
9738                 }
9739
9740                 if (r_refdef.fogenabled)
9741                 {
9742                         alpha = RSurf_FogVertex(v3f);
9743                         VectorScale(c4f, alpha, c4f);
9744                         alpha = RSurf_FogVertex(v3f + 3);
9745                         VectorScale(c4f + 4, alpha, c4f + 4);
9746                         alpha = RSurf_FogVertex(v3f + 6);
9747                         VectorScale(c4f + 8, alpha, c4f + 8);
9748                 }
9749
9750                 v3f += 9;
9751                 c4f += 12;
9752                 t2f += 6;
9753                 numtris++;
9754         }
9755
9756         if (numtris > 0)
9757         {
9758                 r_refdef.stats[r_stat_drawndecals] += numtris;
9759
9760                 // now render the decals all at once
9761                 // (this assumes they all use one particle font texture!)
9762                 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);
9763 //              R_Mesh_ResetTextureState();
9764                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9765                 GL_DepthMask(false);
9766                 GL_DepthRange(0, 1);
9767                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9768                 GL_DepthTest(true);
9769                 GL_CullFace(GL_NONE);
9770                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9771                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9772                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9773         }
9774 }
9775
9776 static void R_DrawModelDecals(void)
9777 {
9778         int i, numdecals;
9779
9780         // fade faster when there are too many decals
9781         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9782         for (i = 0;i < r_refdef.scene.numentities;i++)
9783                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9784
9785         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9786         for (i = 0;i < r_refdef.scene.numentities;i++)
9787                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9788                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9789
9790         R_DecalSystem_ApplySplatEntitiesQueue();
9791
9792         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9793         for (i = 0;i < r_refdef.scene.numentities;i++)
9794                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9795
9796         r_refdef.stats[r_stat_totaldecals] += numdecals;
9797
9798         if (r_showsurfaces.integer || !r_drawdecals.integer)
9799                 return;
9800
9801         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9802
9803         for (i = 0;i < r_refdef.scene.numentities;i++)
9804         {
9805                 if (!r_refdef.viewcache.entityvisible[i])
9806                         continue;
9807                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9808                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9809         }
9810 }
9811
9812 static void R_DrawDebugModel(void)
9813 {
9814         entity_render_t *ent = rsurface.entity;
9815         int j, flagsmask;
9816         const msurface_t *surface;
9817         model_t *model = ent->model;
9818
9819         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9820                 return;
9821
9822         if (r_showoverdraw.value > 0)
9823         {
9824                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9825                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9826                 R_SetupShader_Generic_NoTexture(false, false);
9827                 GL_DepthTest(false);
9828                 GL_DepthMask(false);
9829                 GL_DepthRange(0, 1);
9830                 GL_BlendFunc(GL_ONE, GL_ONE);
9831                 for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
9832                 {
9833                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9834                                 continue;
9835                         surface = model->data_surfaces + j;
9836                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9837                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9838                         {
9839                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9840                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9841                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9842                                         GL_Color(c, 0, 0, 1.0f);
9843                                 else if (ent == r_refdef.scene.worldentity)
9844                                         GL_Color(c, c, c, 1.0f);
9845                                 else
9846                                         GL_Color(0, c, 0, 1.0f);
9847                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9848                                 RSurf_DrawBatch();
9849                         }
9850                 }
9851                 rsurface.texture = NULL;
9852         }
9853
9854         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9855
9856 //      R_Mesh_ResetTextureState();
9857         R_SetupShader_Generic_NoTexture(false, false);
9858         GL_DepthRange(0, 1);
9859         GL_DepthTest(!r_showdisabledepthtest.integer);
9860         GL_DepthMask(false);
9861         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9862
9863         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9864         {
9865                 int triangleindex;
9866                 int bihleafindex;
9867                 qbool cullbox = false;
9868                 const q3mbrush_t *brush;
9869                 const bih_t *bih = &model->collision_bih;
9870                 const bih_leaf_t *bihleaf;
9871                 float vertex3f[3][3];
9872                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9873                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9874                 {
9875                         if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs))
9876                                 continue;
9877                         switch (bihleaf->type)
9878                         {
9879                         case BIH_BRUSH:
9880                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9881                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9882                                 {
9883                                         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);
9884                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9885                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9886                                 }
9887                                 break;
9888                         case BIH_COLLISIONTRIANGLE:
9889                                 triangleindex = bihleaf->itemindex;
9890                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9891                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9892                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9893                                 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);
9894                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9895                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9896                                 break;
9897                         case BIH_RENDERTRIANGLE:
9898                                 triangleindex = bihleaf->itemindex;
9899                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9900                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9901                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9902                                 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);
9903                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9904                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9905                                 break;
9906                         }
9907                 }
9908         }
9909
9910         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9911
9912 #ifndef USE_GLES2
9913         if (r_showtris.value > 0 && qglPolygonMode)
9914         {
9915                 if (r_showdisabledepthtest.integer)
9916                 {
9917                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9918                         GL_DepthMask(false);
9919                 }
9920                 else
9921                 {
9922                         GL_BlendFunc(GL_ONE, GL_ZERO);
9923                         GL_DepthMask(true);
9924                 }
9925                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9926                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9927                 {
9928                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9929                                 continue;
9930                         surface = model->data_surfaces + j;
9931                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9932                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9933                         {
9934                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9935                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9936                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9937                                 else if (ent == r_refdef.scene.worldentity)
9938                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9939                                 else
9940                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9941                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9942                                 RSurf_DrawBatch();
9943                         }
9944                 }
9945                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9946                 rsurface.texture = NULL;
9947         }
9948
9949 # if 0
9950         // FIXME!  implement r_shownormals with just triangles
9951         if (r_shownormals.value != 0 && qglBegin)
9952         {
9953                 int l, k;
9954                 vec3_t v;
9955                 if (r_showdisabledepthtest.integer)
9956                 {
9957                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9958                         GL_DepthMask(false);
9959                 }
9960                 else
9961                 {
9962                         GL_BlendFunc(GL_ONE, GL_ZERO);
9963                         GL_DepthMask(true);
9964                 }
9965                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9966                 {
9967                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9968                                 continue;
9969                         surface = model->data_surfaces + j;
9970                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9971                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9972                         {
9973                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9974                                 qglBegin(GL_LINES);
9975                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9976                                 {
9977                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9978                                         {
9979                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9980                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9981                                                 qglVertex3f(v[0], v[1], v[2]);
9982                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9983                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9984                                                 qglVertex3f(v[0], v[1], v[2]);
9985                                         }
9986                                 }
9987                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9988                                 {
9989                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9990                                         {
9991                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9992                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9993                                                 qglVertex3f(v[0], v[1], v[2]);
9994                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9995                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9996                                                 qglVertex3f(v[0], v[1], v[2]);
9997                                         }
9998                                 }
9999                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10000                                 {
10001                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10002                                         {
10003                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10004                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10005                                                 qglVertex3f(v[0], v[1], v[2]);
10006                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10007                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10008                                                 qglVertex3f(v[0], v[1], v[2]);
10009                                         }
10010                                 }
10011                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10012                                 {
10013                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10014                                         {
10015                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10016                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10017                                                 qglVertex3f(v[0], v[1], v[2]);
10018                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10019                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10020                                                 qglVertex3f(v[0], v[1], v[2]);
10021                                         }
10022                                 }
10023                                 qglEnd();
10024                                 CHECKGLERROR
10025                         }
10026                 }
10027                 rsurface.texture = NULL;
10028         }
10029 # endif
10030 #endif
10031 }
10032
10033 int r_maxsurfacelist = 0;
10034 const msurface_t **r_surfacelist = NULL;
10035 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
10036 {
10037         int i, j, flagsmask;
10038         model_t *model = ent->model;
10039         msurface_t *surfaces;
10040         unsigned char *update;
10041         int numsurfacelist = 0;
10042         if (model == NULL)
10043                 return;
10044
10045         if (r_maxsurfacelist < model->num_surfaces)
10046         {
10047                 r_maxsurfacelist = model->num_surfaces;
10048                 if (r_surfacelist)
10049                         Mem_Free((msurface_t **)r_surfacelist);
10050                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10051         }
10052
10053         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10054                 RSurf_ActiveModelEntity(ent, false, false, false);
10055         else if (prepass)
10056                 RSurf_ActiveModelEntity(ent, true, true, true);
10057         else if (depthonly)
10058                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10059         else
10060                 RSurf_ActiveModelEntity(ent, true, true, false);
10061
10062         surfaces = model->data_surfaces;
10063         update = model->brushq1.lightmapupdateflags;
10064
10065         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10066
10067         if (debug)
10068         {
10069                 R_DrawDebugModel();
10070                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10071                 return;
10072         }
10073
10074         // check if this is an empty model
10075         if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
10076                 return;
10077
10078         rsurface.lightmaptexture = NULL;
10079         rsurface.deluxemaptexture = NULL;
10080         rsurface.uselightmaptexture = false;
10081         rsurface.texture = NULL;
10082         rsurface.rtlight = NULL;
10083         numsurfacelist = 0;
10084
10085         // add visible surfaces to draw list
10086         if (ent == r_refdef.scene.worldentity)
10087         {
10088                 // for the world entity, check surfacevisible
10089                 for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
10090                 {
10091                         j = model->modelsurfaces_sorted[i];
10092                         if (r_refdef.viewcache.world_surfacevisible[j])
10093                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10094                 }
10095
10096                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10097                 if (!numsurfacelist)
10098                 {
10099                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10100                         return;
10101                 }
10102         }
10103         else if (ui)
10104         {
10105                 // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
10106                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10107                         r_surfacelist[numsurfacelist++] = surfaces + i;
10108         }
10109         else
10110         {
10111                 // add all surfaces
10112                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10113                         r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
10114         }
10115
10116         /*
10117          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10118          * using style chains because most styles do not change on most frames, and most
10119          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10120          * break this rule and animate most surfaces.
10121          */
10122         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10123         {
10124                 model_brush_lightstyleinfo_t *style;
10125
10126                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10127                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10128                 {
10129                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10130                         {
10131                                 int* list = style->surfacelist;
10132                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10133                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10134                                 for (j = 0; j < style->numsurfaces; j++)
10135                                         update[list[j]] = true;
10136                         }
10137                 }
10138                 // Now check if update flags are set on any surfaces that are visible
10139                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10140                 {
10141                         /*
10142                          * We can do less frequent texture uploads (approximately 10hz for animated
10143                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10144                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10145                          * use model->num_surfaces, not nummodelsurfaces.
10146                          */
10147                         for (i = 0; i < model->num_surfaces;i++)
10148                                 if (update[i])
10149                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10150                 }
10151                 else
10152                 {
10153                         for (i = 0; i < numsurfacelist; i++)
10154                                 if (update[r_surfacelist[i] - surfaces])
10155                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10156                 }
10157         }
10158
10159         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10160
10161         // add to stats if desired
10162         if (r_speeds.integer && !skysurfaces && !depthonly)
10163         {
10164                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10165                 for (j = 0;j < numsurfacelist;j++)
10166                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10167         }
10168
10169         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10170 }
10171
10172 void R_DebugLine(vec3_t start, vec3_t end)
10173 {
10174         model_t *mod = CL_Mesh_UI();
10175         msurface_t *surf;
10176         int e0, e1, e2, e3;
10177         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10178         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10179         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10180         vec4_t w[2], s[2];
10181
10182         // transform to screen coords first
10183         Vector4Set(w[0], start[0], start[1], start[2], 1);
10184         Vector4Set(w[1], end[0], end[1], end[2], 1);
10185         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10186         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10187         x1 = s[0][0] * vid_conwidth.value / vid.mode.width;
10188         y1 = (vid.mode.height - s[0][1]) * vid_conheight.value / vid.mode.height;
10189         x2 = s[1][0] * vid_conwidth.value / vid.mode.width;
10190         y2 = (vid.mode.height - s[1][1]) * vid_conheight.value / vid.mode.height;
10191         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10192
10193         // add the line to the UI mesh for drawing later
10194
10195         // width is measured in real pixels
10196         if (fabs(x2 - x1) > fabs(y2 - y1))
10197         {
10198                 offsetx = 0;
10199                 offsety = 0.5f * width * vid_conheight.value / vid.mode.height;
10200         }
10201         else
10202         {
10203                 offsetx = 0.5f * width * vid_conwidth.value / vid.mode.width;
10204                 offsety = 0;
10205         }
10206         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);
10207         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10208         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10209         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10210         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10211         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10212         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10213
10214 }
10215
10216
10217 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)
10218 {
10219         static texture_t texture;
10220
10221         // fake enough texture and surface state to render this geometry
10222
10223         texture.update_lastrenderframe = -1; // regenerate this texture
10224         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10225         texture.basealpha = 1.0f;
10226         texture.currentskinframe = skinframe;
10227         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10228         texture.offsetmapping = OFFSETMAPPING_OFF;
10229         texture.offsetscale = 1;
10230         texture.specularscalemod = 1;
10231         texture.specularpowermod = 1;
10232         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10233
10234         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10235 }
10236
10237 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)
10238 {
10239         static msurface_t surface;
10240         const msurface_t *surfacelist = &surface;
10241
10242         // fake enough texture and surface state to render this geometry
10243         surface.texture = texture;
10244         surface.num_triangles = numtriangles;
10245         surface.num_firsttriangle = firsttriangle;
10246         surface.num_vertices = numvertices;
10247         surface.num_firstvertex = firstvertex;
10248
10249         // now render it
10250         rsurface.texture = R_GetCurrentTexture(surface.texture);
10251         rsurface.lightmaptexture = NULL;
10252         rsurface.deluxemaptexture = NULL;
10253         rsurface.uselightmaptexture = false;
10254         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10255 }