]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Fix crash in q3bsp loading on submodels where it was adding the submodelsurfaces_star...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qbool r_loadnormalmap;
48 static qbool r_loadgloss;
49 qbool r_loadfog;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CF_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CF_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CF_CLIENT | CF_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CF_CLIENT | CF_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
208 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
210
211 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
213
214 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
216 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
217 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
220
221 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
228 cvar_t r_hdr_irisadaptation_fade_up = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
229 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
230 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
231
232 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
233
234 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
235
236 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
237
238 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
239
240 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
241 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
242 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
244
245 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
247
248 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
249
250 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
251 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
252 {
253         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
254         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
255         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
256         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
257 };
258
259 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
260 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
261 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
262
263 extern cvar_t v_glslgamma_2d;
264
265 extern qbool v_flipped_state;
266
267 r_framebufferstate_t r_fb;
268
269 /// shadow volume bsp struct with automatically growing nodes buffer
270 svbsp_t r_svbsp;
271
272 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
273
274 rtexture_t *r_texture_blanknormalmap;
275 rtexture_t *r_texture_white;
276 rtexture_t *r_texture_grey128;
277 rtexture_t *r_texture_black;
278 rtexture_t *r_texture_notexture;
279 rtexture_t *r_texture_whitecube;
280 rtexture_t *r_texture_normalizationcube;
281 rtexture_t *r_texture_fogattenuation;
282 rtexture_t *r_texture_fogheighttexture;
283 rtexture_t *r_texture_gammaramps;
284 unsigned int r_texture_gammaramps_serial;
285 //rtexture_t *r_texture_fogintensity;
286 rtexture_t *r_texture_reflectcube;
287
288 // TODO: hash lookups?
289 typedef struct cubemapinfo_s
290 {
291         char basename[64];
292         rtexture_t *texture;
293 }
294 cubemapinfo_t;
295
296 int r_texture_numcubemaps;
297 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
298
299 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
300 unsigned int r_numqueries;
301 unsigned int r_maxqueries;
302
303 typedef struct r_qwskincache_s
304 {
305         char name[MAX_QPATH];
306         skinframe_t *skinframe;
307 }
308 r_qwskincache_t;
309
310 static r_qwskincache_t *r_qwskincache;
311 static int r_qwskincache_size;
312
313 /// vertex coordinates for a quad that covers the screen exactly
314 extern const float r_screenvertex3f[12];
315 const float r_screenvertex3f[12] =
316 {
317         0, 0, 0,
318         1, 0, 0,
319         1, 1, 0,
320         0, 1, 0
321 };
322
323 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
324 {
325         int i;
326         for (i = 0;i < verts;i++)
327         {
328                 out[0] = in[0] * r;
329                 out[1] = in[1] * g;
330                 out[2] = in[2] * b;
331                 out[3] = in[3];
332                 in += 4;
333                 out += 4;
334         }
335 }
336
337 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
338 {
339         int i;
340         for (i = 0;i < verts;i++)
341         {
342                 out[0] = r;
343                 out[1] = g;
344                 out[2] = b;
345                 out[3] = a;
346                 out += 4;
347         }
348 }
349
350 // FIXME: move this to client?
351 void FOG_clear(void)
352 {
353         if (gamemode == GAME_NEHAHRA)
354         {
355                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
356                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
357                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
358                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
359                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
360         }
361         r_refdef.fog_density = 0;
362         r_refdef.fog_red = 0;
363         r_refdef.fog_green = 0;
364         r_refdef.fog_blue = 0;
365         r_refdef.fog_alpha = 1;
366         r_refdef.fog_start = 0;
367         r_refdef.fog_end = 16384;
368         r_refdef.fog_height = 1<<30;
369         r_refdef.fog_fadedepth = 128;
370         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
371 }
372
373 static void R_BuildBlankTextures(void)
374 {
375         unsigned char data[4];
376         data[2] = 128; // normal X
377         data[1] = 128; // normal Y
378         data[0] = 255; // normal Z
379         data[3] = 255; // height
380         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 255;
382         data[1] = 255;
383         data[2] = 255;
384         data[3] = 255;
385         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 128;
387         data[1] = 128;
388         data[2] = 128;
389         data[3] = 255;
390         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391         data[0] = 0;
392         data[1] = 0;
393         data[2] = 0;
394         data[3] = 255;
395         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
396 }
397
398 static void R_BuildNoTexture(void)
399 {
400         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
401 }
402
403 static void R_BuildWhiteCube(void)
404 {
405         unsigned char data[6*1*1*4];
406         memset(data, 255, sizeof(data));
407         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
408 }
409
410 static void R_BuildNormalizationCube(void)
411 {
412         int x, y, side;
413         vec3_t v;
414         vec_t s, t, intensity;
415 #define NORMSIZE 64
416         unsigned char *data;
417         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
418         for (side = 0;side < 6;side++)
419         {
420                 for (y = 0;y < NORMSIZE;y++)
421                 {
422                         for (x = 0;x < NORMSIZE;x++)
423                         {
424                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
425                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
426                                 switch(side)
427                                 {
428                                 default:
429                                 case 0:
430                                         v[0] = 1;
431                                         v[1] = -t;
432                                         v[2] = -s;
433                                         break;
434                                 case 1:
435                                         v[0] = -1;
436                                         v[1] = -t;
437                                         v[2] = s;
438                                         break;
439                                 case 2:
440                                         v[0] = s;
441                                         v[1] = 1;
442                                         v[2] = t;
443                                         break;
444                                 case 3:
445                                         v[0] = s;
446                                         v[1] = -1;
447                                         v[2] = -t;
448                                         break;
449                                 case 4:
450                                         v[0] = s;
451                                         v[1] = -t;
452                                         v[2] = 1;
453                                         break;
454                                 case 5:
455                                         v[0] = -s;
456                                         v[1] = -t;
457                                         v[2] = -1;
458                                         break;
459                                 }
460                                 intensity = 127.0f / sqrt(DotProduct(v, v));
461                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
462                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
463                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
464                                 data[((side*64+y)*64+x)*4+3] = 255;
465                         }
466                 }
467         }
468         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
469         Mem_Free(data);
470 }
471
472 static void R_BuildFogTexture(void)
473 {
474         int x, b;
475 #define FOGWIDTH 256
476         unsigned char data1[FOGWIDTH][4];
477         //unsigned char data2[FOGWIDTH][4];
478         double d, r, alpha;
479
480         r_refdef.fogmasktable_start = r_refdef.fog_start;
481         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
482         r_refdef.fogmasktable_range = r_refdef.fogrange;
483         r_refdef.fogmasktable_density = r_refdef.fog_density;
484
485         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
486         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
487         {
488                 d = (x * r - r_refdef.fogmasktable_start);
489                 if(developer_extra.integer)
490                         Con_DPrintf("%f ", d);
491                 d = max(0, d);
492                 if (r_fog_exp2.integer)
493                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
494                 else
495                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
496                 if(developer_extra.integer)
497                         Con_DPrintf(" : %f ", alpha);
498                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
499                 if(developer_extra.integer)
500                         Con_DPrintf(" = %f\n", alpha);
501                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
502         }
503
504         for (x = 0;x < FOGWIDTH;x++)
505         {
506                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
507                 data1[x][0] = b;
508                 data1[x][1] = b;
509                 data1[x][2] = b;
510                 data1[x][3] = 255;
511                 //data2[x][0] = 255 - b;
512                 //data2[x][1] = 255 - b;
513                 //data2[x][2] = 255 - b;
514                 //data2[x][3] = 255;
515         }
516         if (r_texture_fogattenuation)
517         {
518                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
519                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
520         }
521         else
522         {
523                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
524                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
525         }
526 }
527
528 static void R_BuildFogHeightTexture(void)
529 {
530         unsigned char *inpixels;
531         int size;
532         int x;
533         int y;
534         int j;
535         float c[4];
536         float f;
537         inpixels = NULL;
538         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
539         if (r_refdef.fogheighttexturename[0])
540                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
541         if (!inpixels)
542         {
543                 r_refdef.fog_height_tablesize = 0;
544                 if (r_texture_fogheighttexture)
545                         R_FreeTexture(r_texture_fogheighttexture);
546                 r_texture_fogheighttexture = NULL;
547                 if (r_refdef.fog_height_table2d)
548                         Mem_Free(r_refdef.fog_height_table2d);
549                 r_refdef.fog_height_table2d = NULL;
550                 if (r_refdef.fog_height_table1d)
551                         Mem_Free(r_refdef.fog_height_table1d);
552                 r_refdef.fog_height_table1d = NULL;
553                 return;
554         }
555         size = image_width;
556         r_refdef.fog_height_tablesize = size;
557         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
558         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
559         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
560         Mem_Free(inpixels);
561         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
562         // average fog color table accounting for every fog layer between a point
563         // and the camera.  (Note: attenuation is handled separately!)
564         for (y = 0;y < size;y++)
565         {
566                 for (x = 0;x < size;x++)
567                 {
568                         Vector4Clear(c);
569                         f = 0;
570                         if (x < y)
571                         {
572                                 for (j = x;j <= y;j++)
573                                 {
574                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
575                                         f++;
576                                 }
577                         }
578                         else
579                         {
580                                 for (j = x;j >= y;j--)
581                                 {
582                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
583                                         f++;
584                                 }
585                         }
586                         f = 1.0f / f;
587                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
588                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
589                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
590                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
591                 }
592         }
593         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
594 }
595
596 //=======================================================================================================================================================
597
598 static const char *builtinshaderstrings[] =
599 {
600 #include "shader_glsl.h"
601 0
602 };
603
604 //=======================================================================================================================================================
605
606 typedef struct shaderpermutationinfo_s
607 {
608         const char *pretext;
609         const char *name;
610 }
611 shaderpermutationinfo_t;
612
613 typedef struct shadermodeinfo_s
614 {
615         const char *sourcebasename;
616         const char *extension;
617         const char **builtinshaderstrings;
618         const char *pretext;
619         const char *name;
620         char *filename;
621         char *builtinstring;
622         int builtincrc;
623 }
624 shadermodeinfo_t;
625
626 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
627 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
628 {
629         {"#define USEDIFFUSE\n", " diffuse"},
630         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
631         {"#define USEVIEWTINT\n", " viewtint"},
632         {"#define USECOLORMAPPING\n", " colormapping"},
633         {"#define USESATURATION\n", " saturation"},
634         {"#define USEFOGINSIDE\n", " foginside"},
635         {"#define USEFOGOUTSIDE\n", " fogoutside"},
636         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
637         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
638         {"#define USEGAMMARAMPS\n", " gammaramps"},
639         {"#define USECUBEFILTER\n", " cubefilter"},
640         {"#define USEGLOW\n", " glow"},
641         {"#define USEBLOOM\n", " bloom"},
642         {"#define USESPECULAR\n", " specular"},
643         {"#define USEPOSTPROCESSING\n", " postprocessing"},
644         {"#define USEREFLECTION\n", " reflection"},
645         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
646         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
647         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
648         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
649         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
650         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
651         {"#define USEALPHAKILL\n", " alphakill"},
652         {"#define USEREFLECTCUBE\n", " reflectcube"},
653         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
654         {"#define USEBOUNCEGRID\n", " bouncegrid"},
655         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
656         {"#define USETRIPPY\n", " trippy"},
657         {"#define USEDEPTHRGB\n", " depthrgb"},
658         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
659         {"#define USESKELETAL\n", " skeletal"},
660         {"#define USEOCCLUDE\n", " occlude"}
661 };
662
663 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
664 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
665 {
666         // SHADERLANGUAGE_GLSL
667         {
668                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
669                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
683                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
684                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
685         },
686 };
687
688 struct r_glsl_permutation_s;
689 typedef struct r_glsl_permutation_s
690 {
691         /// hash lookup data
692         struct r_glsl_permutation_s *hashnext;
693         unsigned int mode;
694         uint64_t permutation;
695
696         /// indicates if we have tried compiling this permutation already
697         qbool compiled;
698         /// 0 if compilation failed
699         int program;
700         // texture units assigned to each detected uniform
701         int tex_Texture_First;
702         int tex_Texture_Second;
703         int tex_Texture_GammaRamps;
704         int tex_Texture_Normal;
705         int tex_Texture_Color;
706         int tex_Texture_Gloss;
707         int tex_Texture_Glow;
708         int tex_Texture_SecondaryNormal;
709         int tex_Texture_SecondaryColor;
710         int tex_Texture_SecondaryGloss;
711         int tex_Texture_SecondaryGlow;
712         int tex_Texture_Pants;
713         int tex_Texture_Shirt;
714         int tex_Texture_FogHeightTexture;
715         int tex_Texture_FogMask;
716         int tex_Texture_LightGrid;
717         int tex_Texture_Lightmap;
718         int tex_Texture_Deluxemap;
719         int tex_Texture_Attenuation;
720         int tex_Texture_Cube;
721         int tex_Texture_Refraction;
722         int tex_Texture_Reflection;
723         int tex_Texture_ShadowMap2D;
724         int tex_Texture_CubeProjection;
725         int tex_Texture_ScreenNormalMap;
726         int tex_Texture_ScreenDiffuse;
727         int tex_Texture_ScreenSpecular;
728         int tex_Texture_ReflectMask;
729         int tex_Texture_ReflectCube;
730         int tex_Texture_BounceGrid;
731         /// locations of detected uniforms in program object, or -1 if not found
732         int loc_Texture_First;
733         int loc_Texture_Second;
734         int loc_Texture_GammaRamps;
735         int loc_Texture_Normal;
736         int loc_Texture_Color;
737         int loc_Texture_Gloss;
738         int loc_Texture_Glow;
739         int loc_Texture_SecondaryNormal;
740         int loc_Texture_SecondaryColor;
741         int loc_Texture_SecondaryGloss;
742         int loc_Texture_SecondaryGlow;
743         int loc_Texture_Pants;
744         int loc_Texture_Shirt;
745         int loc_Texture_FogHeightTexture;
746         int loc_Texture_FogMask;
747         int loc_Texture_LightGrid;
748         int loc_Texture_Lightmap;
749         int loc_Texture_Deluxemap;
750         int loc_Texture_Attenuation;
751         int loc_Texture_Cube;
752         int loc_Texture_Refraction;
753         int loc_Texture_Reflection;
754         int loc_Texture_ShadowMap2D;
755         int loc_Texture_CubeProjection;
756         int loc_Texture_ScreenNormalMap;
757         int loc_Texture_ScreenDiffuse;
758         int loc_Texture_ScreenSpecular;
759         int loc_Texture_ReflectMask;
760         int loc_Texture_ReflectCube;
761         int loc_Texture_BounceGrid;
762         int loc_Alpha;
763         int loc_BloomBlur_Parameters;
764         int loc_ClientTime;
765         int loc_Color_Ambient;
766         int loc_Color_Diffuse;
767         int loc_Color_Specular;
768         int loc_Color_Glow;
769         int loc_Color_Pants;
770         int loc_Color_Shirt;
771         int loc_DeferredColor_Ambient;
772         int loc_DeferredColor_Diffuse;
773         int loc_DeferredColor_Specular;
774         int loc_DeferredMod_Diffuse;
775         int loc_DeferredMod_Specular;
776         int loc_DistortScaleRefractReflect;
777         int loc_EyePosition;
778         int loc_FogColor;
779         int loc_FogHeightFade;
780         int loc_FogPlane;
781         int loc_FogPlaneViewDist;
782         int loc_FogRangeRecip;
783         int loc_LightColor;
784         int loc_LightDir;
785         int loc_LightGridMatrix;
786         int loc_LightGridNormalMatrix;
787         int loc_LightPosition;
788         int loc_OffsetMapping_ScaleSteps;
789         int loc_OffsetMapping_LodDistance;
790         int loc_OffsetMapping_Bias;
791         int loc_PixelSize;
792         int loc_ReflectColor;
793         int loc_ReflectFactor;
794         int loc_ReflectOffset;
795         int loc_RefractColor;
796         int loc_Saturation;
797         int loc_ScreenCenterRefractReflect;
798         int loc_ScreenScaleRefractReflect;
799         int loc_ScreenToDepth;
800         int loc_ShadowMap_Parameters;
801         int loc_ShadowMap_TextureScale;
802         int loc_SpecularPower;
803         int loc_Skeletal_Transform12;
804         int loc_UserVec1;
805         int loc_UserVec2;
806         int loc_UserVec3;
807         int loc_UserVec4;
808         int loc_ColorFringe;
809         int loc_ViewTintColor;
810         int loc_ViewToLight;
811         int loc_ModelToLight;
812         int loc_TexMatrix;
813         int loc_BackgroundTexMatrix;
814         int loc_ModelViewProjectionMatrix;
815         int loc_ModelViewMatrix;
816         int loc_PixelToScreenTexCoord;
817         int loc_ModelToReflectCube;
818         int loc_ShadowMapMatrix;
819         int loc_BloomColorSubtract;
820         int loc_NormalmapScrollBlend;
821         int loc_BounceGridMatrix;
822         int loc_BounceGridIntensity;
823         /// uniform block bindings
824         int ubibind_Skeletal_Transform12_UniformBlock;
825         /// uniform block indices
826         int ubiloc_Skeletal_Transform12_UniformBlock;
827 }
828 r_glsl_permutation_t;
829
830 #define SHADERPERMUTATION_HASHSIZE 256
831
832
833 // non-degradable "lightweight" shader parameters to keep the permutations simpler
834 // these can NOT degrade! only use for simple stuff
835 enum
836 {
837         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
838         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
839         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
840         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
841         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
842         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
843         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
844         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
845         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
846         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
847         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
848         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
849         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
850         SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
851         SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
852 };
853 #define SHADERSTATICPARMS_COUNT 15
854
855 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
856 static int shaderstaticparms_count = 0;
857
858 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
859 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
860
861 extern qbool r_shadow_shadowmapsampler;
862 extern int r_shadow_shadowmappcf;
863 qbool R_CompileShader_CheckStaticParms(void)
864 {
865         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
866         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
867         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
868
869         // detect all
870         if (r_glsl_saturation_redcompensate.integer)
871                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
872         if (r_glsl_vertextextureblend_usebothalphas.integer)
873                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
874         if (r_shadow_glossexact.integer)
875                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
876         if (r_glsl_postprocess.integer)
877         {
878                 if (r_glsl_postprocess_uservec1_enable.integer)
879                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
880                 if (r_glsl_postprocess_uservec2_enable.integer)
881                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
882                 if (r_glsl_postprocess_uservec3_enable.integer)
883                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
884                 if (r_glsl_postprocess_uservec4_enable.integer)
885                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
886         }
887         if (r_fxaa.integer)
888                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
889         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
890                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
891
892         if (r_shadow_shadowmapsampler)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
894         if (r_shadow_shadowmappcf > 1)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
896         else if (r_shadow_shadowmappcf)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
898         if (r_celshading.integer)
899                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
900         if (r_celoutlines.integer)
901                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
902         if (r_colorfringe.value)
903                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
904
905         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
906 }
907
908 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
909         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
910                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
911         else \
912                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
913 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
914 {
915         shaderstaticparms_count = 0;
916
917         // emit all
918         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
919         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
933 }
934
935 /// information about each possible shader permutation
936 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
937 /// currently selected permutation
938 r_glsl_permutation_t *r_glsl_permutation;
939 /// storage for permutations linked in the hash table
940 memexpandablearray_t r_glsl_permutationarray;
941
942 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
943 {
944         //unsigned int hashdepth = 0;
945         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
946         r_glsl_permutation_t *p;
947         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
948         {
949                 if (p->mode == mode && p->permutation == permutation)
950                 {
951                         //if (hashdepth > 10)
952                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
953                         return p;
954                 }
955                 //hashdepth++;
956         }
957         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
958         p->mode = mode;
959         p->permutation = permutation;
960         p->hashnext = r_glsl_permutationhash[mode][hashindex];
961         r_glsl_permutationhash[mode][hashindex] = p;
962         //if (hashdepth > 10)
963         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
964         return p;
965 }
966
967 static char *R_ShaderStrCat(const char **strings)
968 {
969         char *string, *s;
970         const char **p = strings;
971         const char *t;
972         size_t len = 0;
973         for (p = strings;(t = *p);p++)
974                 len += strlen(t);
975         len++;
976         s = string = (char *)Mem_Alloc(r_main_mempool, len);
977         len = 0;
978         for (p = strings;(t = *p);p++)
979         {
980                 len = strlen(t);
981                 memcpy(s, t, len);
982                 s += len;
983         }
984         *s = 0;
985         return string;
986 }
987
988 static char *R_ShaderStrCat(const char **strings);
989 static void R_InitShaderModeInfo(void)
990 {
991         int i, language;
992         shadermodeinfo_t *modeinfo;
993         // 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)
994         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
995         {
996                 for (i = 0; i < SHADERMODE_COUNT; i++)
997                 {
998                         char filename[MAX_QPATH];
999                         modeinfo = &shadermodeinfo[language][i];
1000                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1001                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1002                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1003                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1004                 }
1005         }
1006 }
1007
1008 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1009 {
1010         char *shaderstring;
1011         // if the mode has no filename we have to return the builtin string
1012         if (builtinonly || !modeinfo->filename)
1013                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1014         // note that FS_LoadFile appends a 0 byte to make it a valid string
1015         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1016         if (shaderstring)
1017         {
1018                 if (printfromdisknotice)
1019                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1020                 return shaderstring;
1021         }
1022         // fall back to builtinstring
1023         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1024 }
1025
1026 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1027 {
1028         int i;
1029         int ubibind;
1030         int sampler;
1031         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1032         char *sourcestring;
1033         char permutationname[256];
1034         int vertstrings_count = 0;
1035         int geomstrings_count = 0;
1036         int fragstrings_count = 0;
1037         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1038         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1039         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1040
1041         if (p->compiled)
1042                 return;
1043         p->compiled = true;
1044         p->program = 0;
1045
1046         permutationname[0] = 0;
1047         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1048
1049         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1050
1051         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1052         if(vid.support.glshaderversion >= 140)
1053         {
1054                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1055                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1056                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1057                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1058                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1059                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1060         }
1061         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1062         else if(vid.support.glshaderversion >= 130)
1063         {
1064                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1065                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1066                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1067                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1068                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1069                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1070         }
1071         // if we can do #version 120, we should (this adds the invariant keyword)
1072         else if(vid.support.glshaderversion >= 120)
1073         {
1074                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1075                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1076                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1077                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1078                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1079                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1080         }
1081         // GLES also adds several things from GLSL120
1082         switch(vid.renderpath)
1083         {
1084         case RENDERPATH_GLES2:
1085                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1086                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1087                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1088                 break;
1089         default:
1090                 break;
1091         }
1092
1093         // the first pretext is which type of shader to compile as
1094         // (later these will all be bound together as a program object)
1095         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1096         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1097         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1098
1099         // the second pretext is the mode (for example a light source)
1100         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1101         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1102         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1103         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1104
1105         // now add all the permutation pretexts
1106         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1107         {
1108                 if (permutation & (1ll<<i))
1109                 {
1110                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1111                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1112                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1113                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1114                 }
1115                 else
1116                 {
1117                         // keep line numbers correct
1118                         vertstrings_list[vertstrings_count++] = "\n";
1119                         geomstrings_list[geomstrings_count++] = "\n";
1120                         fragstrings_list[fragstrings_count++] = "\n";
1121                 }
1122         }
1123
1124         // add static parms
1125         R_CompileShader_AddStaticParms(mode, permutation);
1126         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1127         vertstrings_count += shaderstaticparms_count;
1128         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1129         geomstrings_count += shaderstaticparms_count;
1130         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1131         fragstrings_count += shaderstaticparms_count;
1132
1133         // now append the shader text itself
1134         vertstrings_list[vertstrings_count++] = sourcestring;
1135         geomstrings_list[geomstrings_count++] = sourcestring;
1136         fragstrings_list[fragstrings_count++] = sourcestring;
1137
1138         // we don't currently use geometry shaders for anything, so just empty the list
1139         geomstrings_count = 0;
1140
1141         // compile the shader program
1142         if (vertstrings_count + geomstrings_count + fragstrings_count)
1143                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1144         if (p->program)
1145         {
1146                 CHECKGLERROR
1147                 qglUseProgram(p->program);CHECKGLERROR
1148                 // look up all the uniform variable names we care about, so we don't
1149                 // have to look them up every time we set them
1150
1151 #if 0
1152                 // debugging aid
1153                 {
1154                         GLint activeuniformindex = 0;
1155                         GLint numactiveuniforms = 0;
1156                         char uniformname[128];
1157                         GLsizei uniformnamelength = 0;
1158                         GLint uniformsize = 0;
1159                         GLenum uniformtype = 0;
1160                         memset(uniformname, 0, sizeof(uniformname));
1161                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1162                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1163                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1164                         {
1165                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1166                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1167                         }
1168                 }
1169 #endif
1170
1171                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1172                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1173                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1174                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1175                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1176                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1177                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1178                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1179                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1180                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1181                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1182                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1183                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1184                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1185                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1186                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1187                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1188                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1189                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1190                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1191                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1192                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1193                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1194                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1195                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1196                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1197                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1198                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1199                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1200                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1201                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1202                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1203                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1204                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1205                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1206                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1207                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1208                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1209                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1210                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1211                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1212                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1213                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1214                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1215                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1216                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1217                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1218                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1219                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1220                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1221                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1222                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1223                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1224                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1225                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1226                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1227                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1228                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1229                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1230                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1231                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1232                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1233                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1234                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1235                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1236                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1237                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1238                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1239                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1240                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1241                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1242                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1243                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1244                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1245                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1246                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1247                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1248                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1249                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1250                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1251                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1252                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1253                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1254                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1255                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1256                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1257                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1258                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1259                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1260                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1261                 // initialize the samplers to refer to the texture units we use
1262                 p->tex_Texture_First = -1;
1263                 p->tex_Texture_Second = -1;
1264                 p->tex_Texture_GammaRamps = -1;
1265                 p->tex_Texture_Normal = -1;
1266                 p->tex_Texture_Color = -1;
1267                 p->tex_Texture_Gloss = -1;
1268                 p->tex_Texture_Glow = -1;
1269                 p->tex_Texture_SecondaryNormal = -1;
1270                 p->tex_Texture_SecondaryColor = -1;
1271                 p->tex_Texture_SecondaryGloss = -1;
1272                 p->tex_Texture_SecondaryGlow = -1;
1273                 p->tex_Texture_Pants = -1;
1274                 p->tex_Texture_Shirt = -1;
1275                 p->tex_Texture_FogHeightTexture = -1;
1276                 p->tex_Texture_FogMask = -1;
1277                 p->tex_Texture_LightGrid = -1;
1278                 p->tex_Texture_Lightmap = -1;
1279                 p->tex_Texture_Deluxemap = -1;
1280                 p->tex_Texture_Attenuation = -1;
1281                 p->tex_Texture_Cube = -1;
1282                 p->tex_Texture_Refraction = -1;
1283                 p->tex_Texture_Reflection = -1;
1284                 p->tex_Texture_ShadowMap2D = -1;
1285                 p->tex_Texture_CubeProjection = -1;
1286                 p->tex_Texture_ScreenNormalMap = -1;
1287                 p->tex_Texture_ScreenDiffuse = -1;
1288                 p->tex_Texture_ScreenSpecular = -1;
1289                 p->tex_Texture_ReflectMask = -1;
1290                 p->tex_Texture_ReflectCube = -1;
1291                 p->tex_Texture_BounceGrid = -1;
1292                 // bind the texture samplers in use
1293                 sampler = 0;
1294                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1295                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1296                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1297                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1298                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1299                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1300                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1301                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1302                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1303                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1304                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1305                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1306                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1307                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1308                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1309                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1310                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1311                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1312                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1313                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1314                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1315                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1316                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1317                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1318                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1319                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1320                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1321                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1322                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1323                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1324                 // get the uniform block indices so we can bind them
1325                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1326 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1327                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1328 #endif
1329                 // clear the uniform block bindings
1330                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1331                 // bind the uniform blocks in use
1332                 ubibind = 0;
1333 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1334                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1335 #endif
1336                 // we're done compiling and setting up the shader, at least until it is used
1337                 CHECKGLERROR
1338                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1339         }
1340         else
1341                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1342
1343         // free the strings
1344         if (sourcestring)
1345                 Mem_Free(sourcestring);
1346 }
1347
1348 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1349 {
1350         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1351         if (r_glsl_permutation != perm)
1352         {
1353                 r_glsl_permutation = perm;
1354                 if (!r_glsl_permutation->program)
1355                 {
1356                         if (!r_glsl_permutation->compiled)
1357                         {
1358                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1359                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1360                         }
1361                         if (!r_glsl_permutation->program)
1362                         {
1363                                 // remove features until we find a valid permutation
1364                                 int i;
1365                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1366                                 {
1367                                         // reduce i more quickly whenever it would not remove any bits
1368                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1369                                         if (!(permutation & j))
1370                                                 continue;
1371                                         permutation -= j;
1372                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1373                                         if (!r_glsl_permutation->compiled)
1374                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1375                                         if (r_glsl_permutation->program)
1376                                                 break;
1377                                 }
1378                                 if (i >= SHADERPERMUTATION_COUNT)
1379                                 {
1380                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1381                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1382                                         qglUseProgram(0);CHECKGLERROR
1383                                         return; // no bit left to clear, entire mode is broken
1384                                 }
1385                         }
1386                 }
1387                 CHECKGLERROR
1388                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1389         }
1390         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1391         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1392         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1393         CHECKGLERROR
1394 }
1395
1396 void R_GLSL_Restart_f(cmd_state_t *cmd)
1397 {
1398         unsigned int i, limit;
1399         switch(vid.renderpath)
1400         {
1401         case RENDERPATH_GL32:
1402         case RENDERPATH_GLES2:
1403                 {
1404                         r_glsl_permutation_t *p;
1405                         r_glsl_permutation = NULL;
1406                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1407                         for (i = 0;i < limit;i++)
1408                         {
1409                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1410                                 {
1411                                         GL_Backend_FreeProgram(p->program);
1412                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1413                                 }
1414                         }
1415                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1416                 }
1417                 break;
1418         }
1419 }
1420
1421 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1422 {
1423         int i, language, mode, dupe;
1424         char *text;
1425         shadermodeinfo_t *modeinfo;
1426         qfile_t *file;
1427
1428         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1429         {
1430                 modeinfo = shadermodeinfo[language];
1431                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1432                 {
1433                         // don't dump the same file multiple times (most or all shaders come from the same file)
1434                         for (dupe = mode - 1;dupe >= 0;dupe--)
1435                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1436                                         break;
1437                         if (dupe >= 0)
1438                                 continue;
1439                         text = modeinfo[mode].builtinstring;
1440                         if (!text)
1441                                 continue;
1442                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1443                         if (file)
1444                         {
1445                                 FS_Print(file, "/* The engine may define the following macros:\n");
1446                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1447                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1448                                         FS_Print(file, modeinfo[i].pretext);
1449                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1450                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1451                                 FS_Print(file, "*/\n");
1452                                 FS_Print(file, text);
1453                                 FS_Close(file);
1454                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1455                         }
1456                         else
1457                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1458                 }
1459         }
1460 }
1461
1462 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1463 {
1464         uint64_t permutation = 0;
1465         if (r_trippy.integer && !notrippy)
1466                 permutation |= SHADERPERMUTATION_TRIPPY;
1467         permutation |= SHADERPERMUTATION_VIEWTINT;
1468         if (t)
1469                 permutation |= SHADERPERMUTATION_DIFFUSE;
1470         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1471                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1472         if (suppresstexalpha)
1473                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1474         if (vid.allowalphatocoverage)
1475                 GL_AlphaToCoverage(false);
1476         switch (vid.renderpath)
1477         {
1478         case RENDERPATH_GL32:
1479         case RENDERPATH_GLES2:
1480                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1481                 if (r_glsl_permutation->tex_Texture_First >= 0)
1482                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1483                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1484                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1485                 break;
1486         }
1487 }
1488
1489 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1490 {
1491         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1492 }
1493
1494 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1495 {
1496         uint64_t permutation = 0;
1497         if (r_trippy.integer && !notrippy)
1498                 permutation |= SHADERPERMUTATION_TRIPPY;
1499         if (depthrgb)
1500                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1501         if (skeletal)
1502                 permutation |= SHADERPERMUTATION_SKELETAL;
1503
1504         if (vid.allowalphatocoverage)
1505                 GL_AlphaToCoverage(false);
1506         switch (vid.renderpath)
1507         {
1508         case RENDERPATH_GL32:
1509         case RENDERPATH_GLES2:
1510                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1511 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1512                 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);
1513 #endif
1514                 break;
1515         }
1516 }
1517
1518 #define BLENDFUNC_ALLOWS_COLORMOD      1
1519 #define BLENDFUNC_ALLOWS_FOG           2
1520 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1521 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1522 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1523 static int R_BlendFuncFlags(int src, int dst)
1524 {
1525         int r = 0;
1526
1527         // a blendfunc allows colormod if:
1528         // a) it can never keep the destination pixel invariant, or
1529         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1530         // this is to prevent unintended side effects from colormod
1531
1532         // a blendfunc allows fog if:
1533         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1534         // this is to prevent unintended side effects from fog
1535
1536         // these checks are the output of fogeval.pl
1537
1538         r |= BLENDFUNC_ALLOWS_COLORMOD;
1539         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1540         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1541         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1542         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1543         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1544         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1545         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1547         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1548         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1549         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1550         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1551         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1552         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1553         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1555         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1557         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1559         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560
1561         return r;
1562 }
1563
1564 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)
1565 {
1566         // select a permutation of the lighting shader appropriate to this
1567         // combination of texture, entity, light source, and fogging, only use the
1568         // minimum features necessary to avoid wasting rendering time in the
1569         // fragment shader on features that are not being used
1570         uint64_t permutation = 0;
1571         unsigned int mode = 0;
1572         int blendfuncflags;
1573         texture_t *t = rsurface.texture;
1574         float m16f[16];
1575         matrix4x4_t tempmatrix;
1576         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1577         if (r_trippy.integer && !notrippy)
1578                 permutation |= SHADERPERMUTATION_TRIPPY;
1579         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1580                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1581         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1582                 permutation |= SHADERPERMUTATION_OCCLUDE;
1583         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1584                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1585         if (rsurfacepass == RSURFPASS_BACKGROUND)
1586         {
1587                 // distorted background
1588                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1589                 {
1590                         mode = SHADERMODE_WATER;
1591                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1592                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1593                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1594                         {
1595                                 // this is the right thing to do for wateralpha
1596                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1597                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1598                         }
1599                         else
1600                         {
1601                                 // this is the right thing to do for entity alpha
1602                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1603                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1604                         }
1605                 }
1606                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1607                 {
1608                         mode = SHADERMODE_REFRACTION;
1609                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1610                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1611                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1612                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1613                 }
1614                 else
1615                 {
1616                         mode = SHADERMODE_GENERIC;
1617                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1618                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1619                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1620                 }
1621                 if (vid.allowalphatocoverage)
1622                         GL_AlphaToCoverage(false);
1623         }
1624         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1625         {
1626                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1627                 {
1628                         switch(t->offsetmapping)
1629                         {
1630                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1631                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1632                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1633                         case OFFSETMAPPING_OFF: break;
1634                         }
1635                 }
1636                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1637                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1638                 // normalmap (deferred prepass), may use alpha test on diffuse
1639                 mode = SHADERMODE_DEFERREDGEOMETRY;
1640                 GL_BlendFunc(GL_ONE, GL_ZERO);
1641                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1642                 if (vid.allowalphatocoverage)
1643                         GL_AlphaToCoverage(false);
1644         }
1645         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1646         {
1647                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1648                 {
1649                         switch(t->offsetmapping)
1650                         {
1651                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1652                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1653                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1654                         case OFFSETMAPPING_OFF: break;
1655                         }
1656                 }
1657                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1658                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1659                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1660                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1661                 // light source
1662                 mode = SHADERMODE_LIGHTSOURCE;
1663                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1664                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1665                 if (VectorLength2(rtlightdiffuse) > 0)
1666                         permutation |= SHADERPERMUTATION_DIFFUSE;
1667                 if (VectorLength2(rtlightspecular) > 0)
1668                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1669                 if (r_refdef.fogenabled)
1670                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1671                 if (t->colormapping)
1672                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1673                 if (r_shadow_usingshadowmap2d)
1674                 {
1675                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1676                         if(r_shadow_shadowmapvsdct)
1677                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1678
1679                         if (r_shadow_shadowmap2ddepthbuffer)
1680                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1681                 }
1682                 if (t->reflectmasktexture)
1683                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1684                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1685                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1686                 if (vid.allowalphatocoverage)
1687                         GL_AlphaToCoverage(false);
1688         }
1689         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1690         {
1691                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1692                 {
1693                         switch(t->offsetmapping)
1694                         {
1695                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1696                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1697                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1698                         case OFFSETMAPPING_OFF: break;
1699                         }
1700                 }
1701                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1702                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1703                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1704                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1705                 // directional model lighting
1706                 mode = SHADERMODE_LIGHTGRID;
1707                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1708                         permutation |= SHADERPERMUTATION_GLOW;
1709                 permutation |= SHADERPERMUTATION_DIFFUSE;
1710                 if (t->glosstexture || t->backgroundglosstexture)
1711                         permutation |= SHADERPERMUTATION_SPECULAR;
1712                 if (r_refdef.fogenabled)
1713                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1714                 if (t->colormapping)
1715                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1716                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1717                 {
1718                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1719                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1720
1721                         if (r_shadow_shadowmap2ddepthbuffer)
1722                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1723                 }
1724                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1725                         permutation |= SHADERPERMUTATION_REFLECTION;
1726                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1727                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1728                 if (t->reflectmasktexture)
1729                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1730                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1731                 {
1732                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1733                         if (r_shadow_bouncegrid_state.directional)
1734                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1735                 }
1736                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1737                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1738                 // when using alphatocoverage, we don't need alphakill
1739                 if (vid.allowalphatocoverage)
1740                 {
1741                         if (r_transparent_alphatocoverage.integer)
1742                         {
1743                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1744                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1745                         }
1746                         else
1747                                 GL_AlphaToCoverage(false);
1748                 }
1749         }
1750         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1751         {
1752                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1753                 {
1754                         switch(t->offsetmapping)
1755                         {
1756                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1757                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1758                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1759                         case OFFSETMAPPING_OFF: break;
1760                         }
1761                 }
1762                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1763                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1764                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1765                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1766                 // directional model lighting
1767                 mode = SHADERMODE_LIGHTDIRECTION;
1768                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1769                         permutation |= SHADERPERMUTATION_GLOW;
1770                 if (VectorLength2(t->render_modellight_diffuse))
1771                         permutation |= SHADERPERMUTATION_DIFFUSE;
1772                 if (VectorLength2(t->render_modellight_specular) > 0)
1773                         permutation |= SHADERPERMUTATION_SPECULAR;
1774                 if (r_refdef.fogenabled)
1775                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1776                 if (t->colormapping)
1777                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1778                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1779                 {
1780                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1781                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1782
1783                         if (r_shadow_shadowmap2ddepthbuffer)
1784                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1785                 }
1786                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1787                         permutation |= SHADERPERMUTATION_REFLECTION;
1788                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1789                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1790                 if (t->reflectmasktexture)
1791                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1792                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1793                 {
1794                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1795                         if (r_shadow_bouncegrid_state.directional)
1796                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1797                 }
1798                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1799                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1800                 // when using alphatocoverage, we don't need alphakill
1801                 if (vid.allowalphatocoverage)
1802                 {
1803                         if (r_transparent_alphatocoverage.integer)
1804                         {
1805                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1806                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1807                         }
1808                         else
1809                                 GL_AlphaToCoverage(false);
1810                 }
1811         }
1812         else
1813         {
1814                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1815                 {
1816                         switch(t->offsetmapping)
1817                         {
1818                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1819                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1820                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1821                         case OFFSETMAPPING_OFF: break;
1822                         }
1823                 }
1824                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1825                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1826                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1827                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1828                 // lightmapped wall
1829                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1830                         permutation |= SHADERPERMUTATION_GLOW;
1831                 if (r_refdef.fogenabled && !ui)
1832                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1833                 if (t->colormapping)
1834                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1835                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1836                 {
1837                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1838                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1839
1840                         if (r_shadow_shadowmap2ddepthbuffer)
1841                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1842                 }
1843                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1844                         permutation |= SHADERPERMUTATION_REFLECTION;
1845                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1846                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1847                 if (t->reflectmasktexture)
1848                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1849                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1850                 {
1851                         // deluxemapping (light direction texture)
1852                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1853                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1854                         else
1855                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1856                         permutation |= SHADERPERMUTATION_DIFFUSE;
1857                         if (VectorLength2(t->render_lightmap_specular) > 0)
1858                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1859                 }
1860                 else if (r_glsl_deluxemapping.integer >= 2)
1861                 {
1862                         // fake deluxemapping (uniform light direction in tangentspace)
1863                         if (rsurface.uselightmaptexture)
1864                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1865                         else
1866                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1867                         permutation |= SHADERPERMUTATION_DIFFUSE;
1868                         if (VectorLength2(t->render_lightmap_specular) > 0)
1869                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1870                 }
1871                 else if (rsurface.uselightmaptexture)
1872                 {
1873                         // ordinary lightmapping (q1bsp, q3bsp)
1874                         mode = SHADERMODE_LIGHTMAP;
1875                 }
1876                 else
1877                 {
1878                         // ordinary vertex coloring (q3bsp)
1879                         mode = SHADERMODE_VERTEXCOLOR;
1880                 }
1881                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1882                 {
1883                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1884                         if (r_shadow_bouncegrid_state.directional)
1885                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1886                 }
1887                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1888                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1889                 // when using alphatocoverage, we don't need alphakill
1890                 if (vid.allowalphatocoverage)
1891                 {
1892                         if (r_transparent_alphatocoverage.integer)
1893                         {
1894                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1895                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1896                         }
1897                         else
1898                                 GL_AlphaToCoverage(false);
1899                 }
1900         }
1901         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1902                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1903         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1904                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1905         switch(vid.renderpath)
1906         {
1907         case RENDERPATH_GL32:
1908         case RENDERPATH_GLES2:
1909                 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);
1910                 RSurf_UploadBuffersForBatch();
1911                 // this has to be after RSurf_PrepareVerticesForBatch
1912                 if (rsurface.batchskeletaltransform3x4buffer)
1913                         permutation |= SHADERPERMUTATION_SKELETAL;
1914                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1915 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1916                 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);
1917 #endif
1918                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1919                 if (mode == SHADERMODE_LIGHTSOURCE)
1920                 {
1921                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1922                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1923                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1924                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1925                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1926                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1927         
1928                         // additive passes are only darkened by fog, not tinted
1929                         if (r_glsl_permutation->loc_FogColor >= 0)
1930                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1931                         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);
1932                 }
1933                 else
1934                 {
1935                         if (mode == SHADERMODE_FLATCOLOR)
1936                         {
1937                                 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]);
1938                         }
1939                         else if (mode == SHADERMODE_LIGHTGRID)
1940                         {
1941                                 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]);
1942                                 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]);
1943                                 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]);
1944                                 // other LightGrid uniforms handled below
1945                         }
1946                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1947                         {
1948                                 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]);
1949                                 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]);
1950                                 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]);
1951                                 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]);
1952                                 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]);
1953                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1954                                 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]);
1955                         }
1956                         else
1957                         {
1958                                 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]);
1959                                 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]);
1960                                 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]);
1961                                 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]);
1962                                 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]);
1963                         }
1964                         // additive passes are only darkened by fog, not tinted
1965                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1966                         {
1967                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1968                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1969                                 else
1970                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1971                         }
1972                         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);
1973                         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]);
1974                         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]);
1975                         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);
1976                         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);
1977                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1978                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1979                         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);
1980                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1981                 }
1982                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1983                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1984                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1985                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1986                 {
1987                         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]);
1988                         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]);
1989                 }
1990                 else
1991                 {
1992                         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]);
1993                         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]);
1994                 }
1995
1996                 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]);
1997                 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));
1998                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1999                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2000                 {
2001                         if (t->pantstexture)
2002                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2003                         else
2004                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2005                 }
2006                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2007                 {
2008                         if (t->shirttexture)
2009                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2010                         else
2011                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2012                 }
2013                 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]);
2014                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2015                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2016                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2017                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2018                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2019                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2020                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2021                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2022                         );
2023                 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);
2024                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2025                 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]);
2026                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2027                 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);}
2028                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2029                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2030                 {
2031                         float m9f[9];
2032                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2033                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2034                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2035                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2036                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2037                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2038                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2039                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2040                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2041                 }
2042
2043                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2044                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2045                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2046                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2047                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2048                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2049                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2050                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2051                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2052                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2053                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2054                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2055                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2056                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2057                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2058                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2059                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2060                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2061                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2062                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2063                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2064                 {
2065                         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);
2066                         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);
2067                         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);
2068                 }
2069                 else
2070                 {
2071                         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);
2072                 }
2073                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2074                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2075                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2076                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2077                 {
2078                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2079                         if (rsurface.rtlight)
2080                         {
2081                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2082                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2083                         }
2084                 }
2085                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2086                 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);
2087                 CHECKGLERROR
2088                 break;
2089         }
2090 }
2091
2092 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2093 {
2094         // select a permutation of the lighting shader appropriate to this
2095         // combination of texture, entity, light source, and fogging, only use the
2096         // minimum features necessary to avoid wasting rendering time in the
2097         // fragment shader on features that are not being used
2098         uint64_t permutation = 0;
2099         unsigned int mode = 0;
2100         const float *lightcolorbase = rtlight->currentcolor;
2101         float ambientscale = rtlight->ambientscale;
2102         float diffusescale = rtlight->diffusescale;
2103         float specularscale = rtlight->specularscale;
2104         // this is the location of the light in view space
2105         vec3_t viewlightorigin;
2106         // this transforms from view space (camera) to light space (cubemap)
2107         matrix4x4_t viewtolight;
2108         matrix4x4_t lighttoview;
2109         float viewtolight16f[16];
2110         // light source
2111         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2112         if (rtlight->currentcubemap != r_texture_whitecube)
2113                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2114         if (diffusescale > 0)
2115                 permutation |= SHADERPERMUTATION_DIFFUSE;
2116         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2117                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2118         if (r_shadow_usingshadowmap2d)
2119         {
2120                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2121                 if (r_shadow_shadowmapvsdct)
2122                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2123
2124                 if (r_shadow_shadowmap2ddepthbuffer)
2125                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2126         }
2127         if (vid.allowalphatocoverage)
2128                 GL_AlphaToCoverage(false);
2129         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2130         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2131         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2132         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2133         switch(vid.renderpath)
2134         {
2135         case RENDERPATH_GL32:
2136         case RENDERPATH_GLES2:
2137                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2138                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2139                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2140                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2141                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2142                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2143                 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]);
2144                 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]);
2145                 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);
2146                 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]);
2147                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2148
2149                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2150                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2151                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2152                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2153                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2154                 break;
2155         }
2156 }
2157
2158 #define SKINFRAME_HASH 1024
2159
2160 typedef struct
2161 {
2162         unsigned int loadsequence; // incremented each level change
2163         memexpandablearray_t array;
2164         skinframe_t *hash[SKINFRAME_HASH];
2165 }
2166 r_skinframe_t;
2167 r_skinframe_t r_skinframe;
2168
2169 void R_SkinFrame_PrepareForPurge(void)
2170 {
2171         r_skinframe.loadsequence++;
2172         // wrap it without hitting zero
2173         if (r_skinframe.loadsequence >= 200)
2174                 r_skinframe.loadsequence = 1;
2175 }
2176
2177 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2178 {
2179         if (!skinframe)
2180                 return;
2181         // mark the skinframe as used for the purging code
2182         skinframe->loadsequence = r_skinframe.loadsequence;
2183 }
2184
2185 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2186 {
2187         if (s == NULL)
2188                 return;
2189         if (s->merged == s->base)
2190                 s->merged = NULL;
2191         R_PurgeTexture(s->stain); s->stain = NULL;
2192         R_PurgeTexture(s->merged); s->merged = NULL;
2193         R_PurgeTexture(s->base); s->base = NULL;
2194         R_PurgeTexture(s->pants); s->pants = NULL;
2195         R_PurgeTexture(s->shirt); s->shirt = NULL;
2196         R_PurgeTexture(s->nmap); s->nmap = NULL;
2197         R_PurgeTexture(s->gloss); s->gloss = NULL;
2198         R_PurgeTexture(s->glow); s->glow = NULL;
2199         R_PurgeTexture(s->fog); s->fog = NULL;
2200         R_PurgeTexture(s->reflect); s->reflect = NULL;
2201         s->loadsequence = 0;
2202 }
2203
2204 void R_SkinFrame_Purge(void)
2205 {
2206         int i;
2207         skinframe_t *s;
2208         for (i = 0;i < SKINFRAME_HASH;i++)
2209         {
2210                 for (s = r_skinframe.hash[i];s;s = s->next)
2211                 {
2212                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2213                                 R_SkinFrame_PurgeSkinFrame(s);
2214                 }
2215         }
2216 }
2217
2218 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2219         skinframe_t *item;
2220         char basename[MAX_QPATH];
2221
2222         Image_StripImageExtension(name, basename, sizeof(basename));
2223
2224         if( last == NULL ) {
2225                 int hashindex;
2226                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2227                 item = r_skinframe.hash[hashindex];
2228         } else {
2229                 item = last->next;
2230         }
2231
2232         // linearly search through the hash bucket
2233         for( ; item ; item = item->next ) {
2234                 if( !strcmp( item->basename, basename ) ) {
2235                         return item;
2236                 }
2237         }
2238         return NULL;
2239 }
2240
2241 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2242 {
2243         skinframe_t *item;
2244         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2245         int hashindex;
2246         char basename[MAX_QPATH];
2247
2248         Image_StripImageExtension(name, basename, sizeof(basename));
2249
2250         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2251         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2252                 if (!strcmp(item->basename, basename) &&
2253                         item->textureflags == compareflags &&
2254                         item->comparewidth == comparewidth &&
2255                         item->compareheight == compareheight &&
2256                         item->comparecrc == comparecrc)
2257                         break;
2258
2259         if (!item)
2260         {
2261                 if (!add)
2262                         return NULL;
2263                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2264                 memset(item, 0, sizeof(*item));
2265                 strlcpy(item->basename, basename, sizeof(item->basename));
2266                 item->textureflags = compareflags;
2267                 item->comparewidth = comparewidth;
2268                 item->compareheight = compareheight;
2269                 item->comparecrc = comparecrc;
2270                 item->next = r_skinframe.hash[hashindex];
2271                 r_skinframe.hash[hashindex] = item;
2272         }
2273         else if (textureflags & TEXF_FORCE_RELOAD)
2274                 R_SkinFrame_PurgeSkinFrame(item);
2275
2276         R_SkinFrame_MarkUsed(item);
2277         return item;
2278 }
2279
2280 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2281         { \
2282                 unsigned long long avgcolor[5], wsum; \
2283                 int pix, comp, w; \
2284                 avgcolor[0] = 0; \
2285                 avgcolor[1] = 0; \
2286                 avgcolor[2] = 0; \
2287                 avgcolor[3] = 0; \
2288                 avgcolor[4] = 0; \
2289                 wsum = 0; \
2290                 for(pix = 0; pix < cnt; ++pix) \
2291                 { \
2292                         w = 0; \
2293                         for(comp = 0; comp < 3; ++comp) \
2294                                 w += getpixel; \
2295                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2296                         { \
2297                                 ++wsum; \
2298                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2299                                 w = getpixel; \
2300                                 for(comp = 0; comp < 3; ++comp) \
2301                                         avgcolor[comp] += getpixel * w; \
2302                                 avgcolor[3] += w; \
2303                         } \
2304                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2305                         avgcolor[4] += getpixel; \
2306                 } \
2307                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2308                         avgcolor[3] = 1; \
2309                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2310                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2311                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2312                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2313         }
2314
2315 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2316 {
2317         skinframe_t *skinframe;
2318
2319         if (cls.state == ca_dedicated)
2320                 return NULL;
2321
2322         // return an existing skinframe if already loaded
2323         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2324         if (skinframe && skinframe->base)
2325                 return skinframe;
2326
2327         // if the skinframe doesn't exist this will create it
2328         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2329 }
2330
2331 extern cvar_t gl_picmip;
2332 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2333 {
2334         int j;
2335         unsigned char *pixels;
2336         unsigned char *bumppixels;
2337         unsigned char *basepixels = NULL;
2338         int basepixels_width = 0;
2339         int basepixels_height = 0;
2340         rtexture_t *ddsbase = NULL;
2341         qbool ddshasalpha = false;
2342         float ddsavgcolor[4];
2343         char basename[MAX_QPATH];
2344         int miplevel = R_PicmipForFlags(textureflags);
2345         int savemiplevel = miplevel;
2346         int mymiplevel;
2347         char vabuf[1024];
2348
2349         if (cls.state == ca_dedicated)
2350                 return NULL;
2351
2352         Image_StripImageExtension(name, basename, sizeof(basename));
2353
2354         // check for DDS texture file first
2355         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2356         {
2357                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2358                 if (basepixels == NULL && fallbacknotexture)
2359                         basepixels = Image_GenerateNoTexture();
2360                 if (basepixels == NULL)
2361                         return NULL;
2362         }
2363
2364         // FIXME handle miplevel
2365
2366         if (developer_loading.integer)
2367                 Con_Printf("loading skin \"%s\"\n", name);
2368
2369         // we've got some pixels to store, so really allocate this new texture now
2370         if (!skinframe)
2371                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2372         textureflags &= ~TEXF_FORCE_RELOAD;
2373         skinframe->stain = NULL;
2374         skinframe->merged = NULL;
2375         skinframe->base = NULL;
2376         skinframe->pants = NULL;
2377         skinframe->shirt = NULL;
2378         skinframe->nmap = NULL;
2379         skinframe->gloss = NULL;
2380         skinframe->glow = NULL;
2381         skinframe->fog = NULL;
2382         skinframe->reflect = NULL;
2383         skinframe->hasalpha = false;
2384         // we could store the q2animname here too
2385
2386         if (ddsbase)
2387         {
2388                 skinframe->base = ddsbase;
2389                 skinframe->hasalpha = ddshasalpha;
2390                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2391                 if (r_loadfog && skinframe->hasalpha)
2392                         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);
2393                 //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]);
2394         }
2395         else
2396         {
2397                 basepixels_width = image_width;
2398                 basepixels_height = image_height;
2399                 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);
2400                 if (textureflags & TEXF_ALPHA)
2401                 {
2402                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2403                         {
2404                                 if (basepixels[j] < 255)
2405                                 {
2406                                         skinframe->hasalpha = true;
2407                                         break;
2408                                 }
2409                         }
2410                         if (r_loadfog && skinframe->hasalpha)
2411                         {
2412                                 // has transparent pixels
2413                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2414                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2415                                 {
2416                                         pixels[j+0] = 255;
2417                                         pixels[j+1] = 255;
2418                                         pixels[j+2] = 255;
2419                                         pixels[j+3] = basepixels[j+3];
2420                                 }
2421                                 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);
2422                                 Mem_Free(pixels);
2423                         }
2424                 }
2425                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2426 #ifndef USE_GLES2
2427                 //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]);
2428                 if (r_savedds && skinframe->base)
2429                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2430                 if (r_savedds && skinframe->fog)
2431                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2432 #endif
2433         }
2434
2435         if (r_loaddds)
2436         {
2437                 mymiplevel = savemiplevel;
2438                 if (r_loadnormalmap)
2439                         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);
2440                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2441                 if (r_loadgloss)
2442                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2443                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2444                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2445                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2446         }
2447
2448         // _norm is the name used by tenebrae and has been adopted as standard
2449         if (r_loadnormalmap && skinframe->nmap == NULL)
2450         {
2451                 mymiplevel = savemiplevel;
2452                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2453                 {
2454                         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);
2455                         Mem_Free(pixels);
2456                         pixels = NULL;
2457                 }
2458                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2459                 {
2460                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2461                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2462                         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);
2463                         Mem_Free(pixels);
2464                         Mem_Free(bumppixels);
2465                 }
2466                 else if (r_shadow_bumpscale_basetexture.value > 0)
2467                 {
2468                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2469                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2470                         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);
2471                         Mem_Free(pixels);
2472                 }
2473 #ifndef USE_GLES2
2474                 if (r_savedds && skinframe->nmap)
2475                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2476 #endif
2477         }
2478
2479         // _luma is supported only for tenebrae compatibility
2480         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2481         // _glow is the preferred name
2482         mymiplevel = savemiplevel;
2483         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))))
2484         {
2485                 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);
2486 #ifndef USE_GLES2
2487                 if (r_savedds && skinframe->glow)
2488                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2489 #endif
2490                 Mem_Free(pixels);pixels = NULL;
2491         }
2492
2493         mymiplevel = savemiplevel;
2494         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2495         {
2496                 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);
2497 #ifndef USE_GLES2
2498                 if (r_savedds && skinframe->gloss)
2499                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2500 #endif
2501                 Mem_Free(pixels);
2502                 pixels = NULL;
2503         }
2504
2505         mymiplevel = savemiplevel;
2506         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2507         {
2508                 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);
2509 #ifndef USE_GLES2
2510                 if (r_savedds && skinframe->pants)
2511                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2512 #endif
2513                 Mem_Free(pixels);
2514                 pixels = NULL;
2515         }
2516
2517         mymiplevel = savemiplevel;
2518         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2519         {
2520                 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);
2521 #ifndef USE_GLES2
2522                 if (r_savedds && skinframe->shirt)
2523                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2524 #endif
2525                 Mem_Free(pixels);
2526                 pixels = NULL;
2527         }
2528
2529         mymiplevel = savemiplevel;
2530         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2531         {
2532                 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);
2533 #ifndef USE_GLES2
2534                 if (r_savedds && skinframe->reflect)
2535                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2536 #endif
2537                 Mem_Free(pixels);
2538                 pixels = NULL;
2539         }
2540
2541         if (basepixels)
2542                 Mem_Free(basepixels);
2543
2544         return skinframe;
2545 }
2546
2547 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)
2548 {
2549         int i;
2550         skinframe_t *skinframe;
2551         char vabuf[1024];
2552
2553         if (cls.state == ca_dedicated)
2554                 return NULL;
2555
2556         // if already loaded just return it, otherwise make a new skinframe
2557         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2558         if (skinframe->base)
2559                 return skinframe;
2560         textureflags &= ~TEXF_FORCE_RELOAD;
2561
2562         skinframe->stain = NULL;
2563         skinframe->merged = NULL;
2564         skinframe->base = NULL;
2565         skinframe->pants = NULL;
2566         skinframe->shirt = NULL;
2567         skinframe->nmap = NULL;
2568         skinframe->gloss = NULL;
2569         skinframe->glow = NULL;
2570         skinframe->fog = NULL;
2571         skinframe->reflect = NULL;
2572         skinframe->hasalpha = false;
2573
2574         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2575         if (!skindata)
2576                 return NULL;
2577
2578         if (developer_loading.integer)
2579                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2580
2581         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2582         {
2583                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2584                 unsigned char *b = a + width * height * 4;
2585                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2586                 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);
2587                 Mem_Free(a);
2588         }
2589         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2590         if (textureflags & TEXF_ALPHA)
2591         {
2592                 for (i = 3;i < width * height * 4;i += 4)
2593                 {
2594                         if (skindata[i] < 255)
2595                         {
2596                                 skinframe->hasalpha = true;
2597                                 break;
2598                         }
2599                 }
2600                 if (r_loadfog && skinframe->hasalpha)
2601                 {
2602                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2603                         memcpy(fogpixels, skindata, width * height * 4);
2604                         for (i = 0;i < width * height * 4;i += 4)
2605                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2606                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2607                         Mem_Free(fogpixels);
2608                 }
2609         }
2610
2611         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2612         //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]);
2613
2614         return skinframe;
2615 }
2616
2617 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2618 {
2619         int i;
2620         int featuresmask;
2621         skinframe_t *skinframe;
2622
2623         if (cls.state == ca_dedicated)
2624                 return NULL;
2625
2626         // if already loaded just return it, otherwise make a new skinframe
2627         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2628         if (skinframe->base)
2629                 return skinframe;
2630         //textureflags &= ~TEXF_FORCE_RELOAD;
2631
2632         skinframe->stain = NULL;
2633         skinframe->merged = NULL;
2634         skinframe->base = NULL;
2635         skinframe->pants = NULL;
2636         skinframe->shirt = NULL;
2637         skinframe->nmap = NULL;
2638         skinframe->gloss = NULL;
2639         skinframe->glow = NULL;
2640         skinframe->fog = NULL;
2641         skinframe->reflect = NULL;
2642         skinframe->hasalpha = false;
2643
2644         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2645         if (!skindata)
2646                 return NULL;
2647
2648         if (developer_loading.integer)
2649                 Con_Printf("loading quake skin \"%s\"\n", name);
2650
2651         // 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)
2652         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2653         memcpy(skinframe->qpixels, skindata, width*height);
2654         skinframe->qwidth = width;
2655         skinframe->qheight = height;
2656
2657         featuresmask = 0;
2658         for (i = 0;i < width * height;i++)
2659                 featuresmask |= palette_featureflags[skindata[i]];
2660
2661         skinframe->hasalpha = false;
2662         // fence textures
2663         if (name[0] == '{')
2664                 skinframe->hasalpha = true;
2665         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2666         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2667         skinframe->qgeneratemerged = true;
2668         skinframe->qgeneratebase = skinframe->qhascolormapping;
2669         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2670
2671         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2672         //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]);
2673
2674         return skinframe;
2675 }
2676
2677 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2678 {
2679         int width;
2680         int height;
2681         unsigned char *skindata;
2682         char vabuf[1024];
2683
2684         if (!skinframe->qpixels)
2685                 return;
2686
2687         if (!skinframe->qhascolormapping)
2688                 colormapped = false;
2689
2690         if (colormapped)
2691         {
2692                 if (!skinframe->qgeneratebase)
2693                         return;
2694         }
2695         else
2696         {
2697                 if (!skinframe->qgeneratemerged)
2698                         return;
2699         }
2700
2701         width = skinframe->qwidth;
2702         height = skinframe->qheight;
2703         skindata = skinframe->qpixels;
2704
2705         if (skinframe->qgeneratenmap)
2706         {
2707                 unsigned char *a, *b;
2708                 skinframe->qgeneratenmap = false;
2709                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2710                 b = a + width * height * 4;
2711                 // use either a custom palette or the quake palette
2712                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2713                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2714                 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);
2715                 Mem_Free(a);
2716         }
2717
2718         if (skinframe->qgenerateglow)
2719         {
2720                 skinframe->qgenerateglow = false;
2721                 if (skinframe->hasalpha) // fence textures
2722                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2723                 else
2724                         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
2725         }
2726
2727         if (colormapped)
2728         {
2729                 skinframe->qgeneratebase = false;
2730                 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);
2731                 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);
2732                 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);
2733         }
2734         else
2735         {
2736                 skinframe->qgeneratemerged = false;
2737                 if (skinframe->hasalpha) // fence textures
2738                         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);
2739                 else
2740                         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);
2741         }
2742
2743         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2744         {
2745                 Mem_Free(skinframe->qpixels);
2746                 skinframe->qpixels = NULL;
2747         }
2748 }
2749
2750 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)
2751 {
2752         int i;
2753         skinframe_t *skinframe;
2754         char vabuf[1024];
2755
2756         if (cls.state == ca_dedicated)
2757                 return NULL;
2758
2759         // if already loaded just return it, otherwise make a new skinframe
2760         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2761         if (skinframe->base)
2762                 return skinframe;
2763         textureflags &= ~TEXF_FORCE_RELOAD;
2764
2765         skinframe->stain = NULL;
2766         skinframe->merged = NULL;
2767         skinframe->base = NULL;
2768         skinframe->pants = NULL;
2769         skinframe->shirt = NULL;
2770         skinframe->nmap = NULL;
2771         skinframe->gloss = NULL;
2772         skinframe->glow = NULL;
2773         skinframe->fog = NULL;
2774         skinframe->reflect = NULL;
2775         skinframe->hasalpha = false;
2776
2777         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2778         if (!skindata)
2779                 return NULL;
2780
2781         if (developer_loading.integer)
2782                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2783
2784         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2785         if ((textureflags & TEXF_ALPHA) && alphapalette)
2786         {
2787                 for (i = 0;i < width * height;i++)
2788                 {
2789                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2790                         {
2791                                 skinframe->hasalpha = true;
2792                                 break;
2793                         }
2794                 }
2795                 if (r_loadfog && skinframe->hasalpha)
2796                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2797         }
2798
2799         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2800         //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]);
2801
2802         return skinframe;
2803 }
2804
2805 skinframe_t *R_SkinFrame_LoadMissing(void)
2806 {
2807         skinframe_t *skinframe;
2808
2809         if (cls.state == ca_dedicated)
2810                 return NULL;
2811
2812         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2813         skinframe->stain = NULL;
2814         skinframe->merged = NULL;
2815         skinframe->base = NULL;
2816         skinframe->pants = NULL;
2817         skinframe->shirt = NULL;
2818         skinframe->nmap = NULL;
2819         skinframe->gloss = NULL;
2820         skinframe->glow = NULL;
2821         skinframe->fog = NULL;
2822         skinframe->reflect = NULL;
2823         skinframe->hasalpha = false;
2824
2825         skinframe->avgcolor[0] = rand() / RAND_MAX;
2826         skinframe->avgcolor[1] = rand() / RAND_MAX;
2827         skinframe->avgcolor[2] = rand() / RAND_MAX;
2828         skinframe->avgcolor[3] = 1;
2829
2830         return skinframe;
2831 }
2832
2833 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2834 {
2835         if (cls.state == ca_dedicated)
2836                 return NULL;
2837
2838         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2839 }
2840
2841 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2842 {
2843         skinframe_t *skinframe;
2844         if (cls.state == ca_dedicated)
2845                 return NULL;
2846         // if already loaded just return it, otherwise make a new skinframe
2847         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2848         if (skinframe->base)
2849                 return skinframe;
2850         textureflags &= ~TEXF_FORCE_RELOAD;
2851         skinframe->stain = NULL;
2852         skinframe->merged = NULL;
2853         skinframe->base = NULL;
2854         skinframe->pants = NULL;
2855         skinframe->shirt = NULL;
2856         skinframe->nmap = NULL;
2857         skinframe->gloss = NULL;
2858         skinframe->glow = NULL;
2859         skinframe->fog = NULL;
2860         skinframe->reflect = NULL;
2861         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2862         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2863         if (!tex)
2864                 return NULL;
2865         if (developer_loading.integer)
2866                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2867         skinframe->base = skinframe->merged = tex;
2868         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2869         return skinframe;
2870 }
2871
2872 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2873 typedef struct suffixinfo_s
2874 {
2875         const char *suffix;
2876         qbool flipx, flipy, flipdiagonal;
2877 }
2878 suffixinfo_t;
2879 static suffixinfo_t suffix[3][6] =
2880 {
2881         {
2882                 {"px",   false, false, false},
2883                 {"nx",   false, false, false},
2884                 {"py",   false, false, false},
2885                 {"ny",   false, false, false},
2886                 {"pz",   false, false, false},
2887                 {"nz",   false, false, false}
2888         },
2889         {
2890                 {"posx", false, false, false},
2891                 {"negx", false, false, false},
2892                 {"posy", false, false, false},
2893                 {"negy", false, false, false},
2894                 {"posz", false, false, false},
2895                 {"negz", false, false, false}
2896         },
2897         {
2898                 {"rt",    true, false,  true},
2899                 {"lf",   false,  true,  true},
2900                 {"ft",    true,  true, false},
2901                 {"bk",   false, false, false},
2902                 {"up",    true, false,  true},
2903                 {"dn",    true, false,  true}
2904         }
2905 };
2906
2907 static int componentorder[4] = {0, 1, 2, 3};
2908
2909 static rtexture_t *R_LoadCubemap(const char *basename)
2910 {
2911         int i, j, cubemapsize, forcefilter;
2912         unsigned char *cubemappixels, *image_buffer;
2913         rtexture_t *cubemaptexture;
2914         char name[256];
2915
2916         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2917         forcefilter = TEXF_FORCELINEAR;
2918         if (basename && basename[0] == '!')
2919         {
2920                 basename++;
2921                 forcefilter = TEXF_FORCENEAREST;
2922         }
2923         // must start 0 so the first loadimagepixels has no requested width/height
2924         cubemapsize = 0;
2925         cubemappixels = NULL;
2926         cubemaptexture = NULL;
2927         // keep trying different suffix groups (posx, px, rt) until one loads
2928         for (j = 0;j < 3 && !cubemappixels;j++)
2929         {
2930                 // load the 6 images in the suffix group
2931                 for (i = 0;i < 6;i++)
2932                 {
2933                         // generate an image name based on the base and and suffix
2934                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2935                         // load it
2936                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2937                         {
2938                                 // an image loaded, make sure width and height are equal
2939                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2940                                 {
2941                                         // if this is the first image to load successfully, allocate the cubemap memory
2942                                         if (!cubemappixels && image_width >= 1)
2943                                         {
2944                                                 cubemapsize = image_width;
2945                                                 // note this clears to black, so unavailable sides are black
2946                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2947                                         }
2948                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2949                                         if (cubemappixels)
2950                                                 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);
2951                                 }
2952                                 else
2953                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2954                                 // free the image
2955                                 Mem_Free(image_buffer);
2956                         }
2957                 }
2958         }
2959         // if a cubemap loaded, upload it
2960         if (cubemappixels)
2961         {
2962                 if (developer_loading.integer)
2963                         Con_Printf("loading cubemap \"%s\"\n", basename);
2964
2965                 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);
2966                 Mem_Free(cubemappixels);
2967         }
2968         else
2969         {
2970                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2971                 if (developer_loading.integer)
2972                 {
2973                         Con_Printf("(tried tried images ");
2974                         for (j = 0;j < 3;j++)
2975                                 for (i = 0;i < 6;i++)
2976                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2977                         Con_Print(" and was unable to find any of them).\n");
2978                 }
2979         }
2980         return cubemaptexture;
2981 }
2982
2983 rtexture_t *R_GetCubemap(const char *basename)
2984 {
2985         int i;
2986         for (i = 0;i < r_texture_numcubemaps;i++)
2987                 if (r_texture_cubemaps[i] != NULL)
2988                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2989                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2990         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2991                 return r_texture_whitecube;
2992         r_texture_numcubemaps++;
2993         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2994         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2995         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2996         return r_texture_cubemaps[i]->texture;
2997 }
2998
2999 static void R_Main_FreeViewCache(void)
3000 {
3001         if (r_refdef.viewcache.entityvisible)
3002                 Mem_Free(r_refdef.viewcache.entityvisible);
3003         if (r_refdef.viewcache.world_pvsbits)
3004                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3005         if (r_refdef.viewcache.world_leafvisible)
3006                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3007         if (r_refdef.viewcache.world_surfacevisible)
3008                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3009         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3010 }
3011
3012 static void R_Main_ResizeViewCache(void)
3013 {
3014         int numentities = r_refdef.scene.numentities;
3015         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3016         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3017         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3018         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3019         if (r_refdef.viewcache.maxentities < numentities)
3020         {
3021                 r_refdef.viewcache.maxentities = numentities;
3022                 if (r_refdef.viewcache.entityvisible)
3023                         Mem_Free(r_refdef.viewcache.entityvisible);
3024                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3025         }
3026         if (r_refdef.viewcache.world_numclusters != numclusters)
3027         {
3028                 r_refdef.viewcache.world_numclusters = numclusters;
3029                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3030                 if (r_refdef.viewcache.world_pvsbits)
3031                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3032                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3033         }
3034         if (r_refdef.viewcache.world_numleafs != numleafs)
3035         {
3036                 r_refdef.viewcache.world_numleafs = numleafs;
3037                 if (r_refdef.viewcache.world_leafvisible)
3038                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3039                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3040         }
3041         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3042         {
3043                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3044                 if (r_refdef.viewcache.world_surfacevisible)
3045                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3046                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3047         }
3048 }
3049
3050 extern rtexture_t *loadingscreentexture;
3051 static void gl_main_start(void)
3052 {
3053         loadingscreentexture = NULL;
3054         r_texture_blanknormalmap = NULL;
3055         r_texture_white = NULL;
3056         r_texture_grey128 = NULL;
3057         r_texture_black = NULL;
3058         r_texture_whitecube = NULL;
3059         r_texture_normalizationcube = NULL;
3060         r_texture_fogattenuation = NULL;
3061         r_texture_fogheighttexture = NULL;
3062         r_texture_gammaramps = NULL;
3063         r_texture_numcubemaps = 0;
3064         r_uniformbufferalignment = 32;
3065
3066         r_loaddds = r_texture_dds_load.integer != 0;
3067         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3068
3069         switch(vid.renderpath)
3070         {
3071         case RENDERPATH_GL32:
3072         case RENDERPATH_GLES2:
3073                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3074                 Cvar_SetValueQuick(&gl_combine, 1);
3075                 Cvar_SetValueQuick(&r_glsl, 1);
3076                 r_loadnormalmap = true;
3077                 r_loadgloss = true;
3078                 r_loadfog = false;
3079 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3080                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3081 #endif
3082                 break;
3083         }
3084
3085         R_AnimCache_Free();
3086         R_FrameData_Reset();
3087         R_BufferData_Reset();
3088
3089         r_numqueries = 0;
3090         r_maxqueries = 0;
3091         memset(r_queries, 0, sizeof(r_queries));
3092
3093         r_qwskincache = NULL;
3094         r_qwskincache_size = 0;
3095
3096         // due to caching of texture_t references, the collision cache must be reset
3097         Collision_Cache_Reset(true);
3098
3099         // set up r_skinframe loading system for textures
3100         memset(&r_skinframe, 0, sizeof(r_skinframe));
3101         r_skinframe.loadsequence = 1;
3102         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3103
3104         r_main_texturepool = R_AllocTexturePool();
3105         R_BuildBlankTextures();
3106         R_BuildNoTexture();
3107         R_BuildWhiteCube();
3108 #ifndef USE_GLES2
3109         R_BuildNormalizationCube();
3110 #endif //USE_GLES2
3111         r_texture_fogattenuation = NULL;
3112         r_texture_fogheighttexture = NULL;
3113         r_texture_gammaramps = NULL;
3114         //r_texture_fogintensity = NULL;
3115         memset(&r_fb, 0, sizeof(r_fb));
3116         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3117         r_glsl_permutation = NULL;
3118         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3119         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3120         memset(&r_svbsp, 0, sizeof (r_svbsp));
3121
3122         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3123         r_texture_numcubemaps = 0;
3124
3125         r_refdef.fogmasktable_density = 0;
3126
3127 #ifdef __ANDROID__
3128         // For Steelstorm Android
3129         // FIXME CACHE the program and reload
3130         // FIXME see possible combinations for SS:BR android
3131         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3132         R_SetupShader_SetPermutationGLSL(0, 12);
3133         R_SetupShader_SetPermutationGLSL(0, 13);
3134         R_SetupShader_SetPermutationGLSL(0, 8388621);
3135         R_SetupShader_SetPermutationGLSL(3, 0);
3136         R_SetupShader_SetPermutationGLSL(3, 2048);
3137         R_SetupShader_SetPermutationGLSL(5, 0);
3138         R_SetupShader_SetPermutationGLSL(5, 2);
3139         R_SetupShader_SetPermutationGLSL(5, 2048);
3140         R_SetupShader_SetPermutationGLSL(5, 8388608);
3141         R_SetupShader_SetPermutationGLSL(11, 1);
3142         R_SetupShader_SetPermutationGLSL(11, 2049);
3143         R_SetupShader_SetPermutationGLSL(11, 8193);
3144         R_SetupShader_SetPermutationGLSL(11, 10241);
3145         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3146 #endif
3147 }
3148
3149 extern unsigned int r_shadow_occlusion_buf;
3150
3151 static void gl_main_shutdown(void)
3152 {
3153         R_RenderTarget_FreeUnused(true);
3154         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3155         R_AnimCache_Free();
3156         R_FrameData_Reset();
3157         R_BufferData_Reset();
3158
3159         R_Main_FreeViewCache();
3160
3161         switch(vid.renderpath)
3162         {
3163         case RENDERPATH_GL32:
3164         case RENDERPATH_GLES2:
3165 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3166                 if (r_maxqueries)
3167                         qglDeleteQueries(r_maxqueries, r_queries);
3168 #endif
3169                 break;
3170         }
3171         r_shadow_occlusion_buf = 0;
3172         r_numqueries = 0;
3173         r_maxqueries = 0;
3174         memset(r_queries, 0, sizeof(r_queries));
3175
3176         r_qwskincache = NULL;
3177         r_qwskincache_size = 0;
3178
3179         // clear out the r_skinframe state
3180         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3181         memset(&r_skinframe, 0, sizeof(r_skinframe));
3182
3183         if (r_svbsp.nodes)
3184                 Mem_Free(r_svbsp.nodes);
3185         memset(&r_svbsp, 0, sizeof (r_svbsp));
3186         R_FreeTexturePool(&r_main_texturepool);
3187         loadingscreentexture = NULL;
3188         r_texture_blanknormalmap = NULL;
3189         r_texture_white = NULL;
3190         r_texture_grey128 = NULL;
3191         r_texture_black = NULL;
3192         r_texture_whitecube = NULL;
3193         r_texture_normalizationcube = NULL;
3194         r_texture_fogattenuation = NULL;
3195         r_texture_fogheighttexture = NULL;
3196         r_texture_gammaramps = NULL;
3197         r_texture_numcubemaps = 0;
3198         //r_texture_fogintensity = NULL;
3199         memset(&r_fb, 0, sizeof(r_fb));
3200         R_GLSL_Restart_f(&cmd_client);
3201
3202         r_glsl_permutation = NULL;
3203         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3204         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3205 }
3206
3207 static void gl_main_newmap(void)
3208 {
3209         // FIXME: move this code to client
3210         char *entities, entname[MAX_QPATH];
3211         if (r_qwskincache)
3212                 Mem_Free(r_qwskincache);
3213         r_qwskincache = NULL;
3214         r_qwskincache_size = 0;
3215         if (cl.worldmodel)
3216         {
3217                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3218                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3219                 {
3220                         CL_ParseEntityLump(entities);
3221                         Mem_Free(entities);
3222                         return;
3223                 }
3224                 if (cl.worldmodel->brush.entities)
3225                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3226         }
3227         R_Main_FreeViewCache();
3228
3229         R_FrameData_Reset();
3230         R_BufferData_Reset();
3231 }
3232
3233 void GL_Main_Init(void)
3234 {
3235         int i;
3236         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3237         R_InitShaderModeInfo();
3238
3239         Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3240         Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3241         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3242         if (gamemode == GAME_NEHAHRA)
3243         {
3244                 Cvar_RegisterVariable (&gl_fogenable);
3245                 Cvar_RegisterVariable (&gl_fogdensity);
3246                 Cvar_RegisterVariable (&gl_fogred);
3247                 Cvar_RegisterVariable (&gl_foggreen);
3248                 Cvar_RegisterVariable (&gl_fogblue);
3249                 Cvar_RegisterVariable (&gl_fogstart);
3250                 Cvar_RegisterVariable (&gl_fogend);
3251                 Cvar_RegisterVariable (&gl_skyclip);
3252         }
3253         Cvar_RegisterVariable(&r_motionblur);
3254         Cvar_RegisterVariable(&r_damageblur);
3255         Cvar_RegisterVariable(&r_motionblur_averaging);
3256         Cvar_RegisterVariable(&r_motionblur_randomize);
3257         Cvar_RegisterVariable(&r_motionblur_minblur);
3258         Cvar_RegisterVariable(&r_motionblur_maxblur);
3259         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3260         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3261         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3262         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3263         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3264         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3265         Cvar_RegisterVariable(&r_depthfirst);
3266         Cvar_RegisterVariable(&r_useinfinitefarclip);
3267         Cvar_RegisterVariable(&r_farclip_base);
3268         Cvar_RegisterVariable(&r_farclip_world);
3269         Cvar_RegisterVariable(&r_nearclip);
3270         Cvar_RegisterVariable(&r_deformvertexes);
3271         Cvar_RegisterVariable(&r_transparent);
3272         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3273         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3274         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3275         Cvar_RegisterVariable(&r_showoverdraw);
3276         Cvar_RegisterVariable(&r_showbboxes);
3277         Cvar_RegisterVariable(&r_showbboxes_client);
3278         Cvar_RegisterVariable(&r_showsurfaces);
3279         Cvar_RegisterVariable(&r_showtris);
3280         Cvar_RegisterVariable(&r_shownormals);
3281         Cvar_RegisterVariable(&r_showlighting);
3282         Cvar_RegisterVariable(&r_showcollisionbrushes);
3283         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3284         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3285         Cvar_RegisterVariable(&r_showdisabledepthtest);
3286         Cvar_RegisterVariable(&r_showspriteedges);
3287         Cvar_RegisterVariable(&r_showparticleedges);
3288         Cvar_RegisterVariable(&r_drawportals);
3289         Cvar_RegisterVariable(&r_drawentities);
3290         Cvar_RegisterVariable(&r_draw2d);
3291         Cvar_RegisterVariable(&r_drawworld);
3292         Cvar_RegisterVariable(&r_cullentities_trace);
3293         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3294         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3295         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3296         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3297         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3298         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3299         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3300         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3301         Cvar_RegisterVariable(&r_sortentities);
3302         Cvar_RegisterVariable(&r_drawviewmodel);
3303         Cvar_RegisterVariable(&r_drawexteriormodel);
3304         Cvar_RegisterVariable(&r_speeds);
3305         Cvar_RegisterVariable(&r_fullbrights);
3306         Cvar_RegisterVariable(&r_wateralpha);
3307         Cvar_RegisterVariable(&r_dynamic);
3308         Cvar_RegisterVariable(&r_fullbright_directed);
3309         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3310         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3311         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3312         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3313         Cvar_RegisterVariable(&r_fullbright);
3314         Cvar_RegisterVariable(&r_shadows);
3315         Cvar_RegisterVariable(&r_shadows_darken);
3316         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3317         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3318         Cvar_RegisterVariable(&r_shadows_throwdistance);
3319         Cvar_RegisterVariable(&r_shadows_throwdirection);
3320         Cvar_RegisterVariable(&r_shadows_focus);
3321         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3322         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3323         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3324         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3325         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3326         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3327         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3328         Cvar_RegisterVariable(&r_fog_exp2);
3329         Cvar_RegisterVariable(&r_fog_clear);
3330         Cvar_RegisterVariable(&r_drawfog);
3331         Cvar_RegisterVariable(&r_transparentdepthmasking);
3332         Cvar_RegisterVariable(&r_transparent_sortmindist);
3333         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3334         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3335         Cvar_RegisterVariable(&r_texture_dds_load);
3336         Cvar_RegisterVariable(&r_texture_dds_save);
3337         Cvar_RegisterVariable(&r_textureunits);
3338         Cvar_RegisterVariable(&gl_combine);
3339         Cvar_RegisterVariable(&r_usedepthtextures);
3340         Cvar_RegisterVariable(&r_viewfbo);
3341         Cvar_RegisterVariable(&r_rendertarget_debug);
3342         Cvar_RegisterVariable(&r_viewscale);
3343         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3344         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3345         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3346         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3347         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3348         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3349         Cvar_RegisterVariable(&r_glsl);
3350         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3351         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3352         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3353         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3354         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3355         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3356         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3357         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3358         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3359         Cvar_RegisterVariable(&r_glsl_postprocess);
3360         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3361         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3362         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3363         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3364         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3365         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3366         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3367         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3368         Cvar_RegisterVariable(&r_celshading);
3369         Cvar_RegisterVariable(&r_celoutlines);
3370
3371         Cvar_RegisterVariable(&r_water);
3372         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3373         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3374         Cvar_RegisterVariable(&r_water_clippingplanebias);
3375         Cvar_RegisterVariable(&r_water_refractdistort);
3376         Cvar_RegisterVariable(&r_water_reflectdistort);
3377         Cvar_RegisterVariable(&r_water_scissormode);
3378         Cvar_RegisterVariable(&r_water_lowquality);
3379         Cvar_RegisterVariable(&r_water_hideplayer);
3380
3381         Cvar_RegisterVariable(&r_lerpsprites);
3382         Cvar_RegisterVariable(&r_lerpmodels);
3383         Cvar_RegisterVariable(&r_nolerp_list);
3384         Cvar_RegisterVariable(&r_lerplightstyles);
3385         Cvar_RegisterVariable(&r_waterscroll);
3386         Cvar_RegisterVariable(&r_bloom);
3387         Cvar_RegisterVariable(&r_colorfringe);
3388         Cvar_RegisterVariable(&r_bloom_colorscale);
3389         Cvar_RegisterVariable(&r_bloom_brighten);
3390         Cvar_RegisterVariable(&r_bloom_blur);
3391         Cvar_RegisterVariable(&r_bloom_resolution);
3392         Cvar_RegisterVariable(&r_bloom_colorexponent);
3393         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3394         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3395         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3396         Cvar_RegisterVariable(&r_hdr_glowintensity);
3397         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3398         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3399         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3400         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3401         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3402         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3403         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3404         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3405         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3406         Cvar_RegisterVariable(&developer_texturelogging);
3407         Cvar_RegisterVariable(&gl_lightmaps);
3408         Cvar_RegisterVariable(&r_test);
3409         Cvar_RegisterVariable(&r_batch_multidraw);
3410         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3411         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3412         Cvar_RegisterVariable(&r_glsl_skeletal);
3413         Cvar_RegisterVariable(&r_glsl_saturation);
3414         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3415         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3416         Cvar_RegisterVariable(&r_framedatasize);
3417         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3418                 Cvar_RegisterVariable(&r_buffermegs[i]);
3419         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3420         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3421         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3422         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3423         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3424                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3425 #ifdef DP_MOBILETOUCH
3426         // GLES devices have terrible depth precision in general, so...
3427         Cvar_SetValueQuick(&r_nearclip, 4);
3428         Cvar_SetValueQuick(&r_farclip_base, 4096);
3429         Cvar_SetValueQuick(&r_farclip_world, 0);
3430         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3431 #endif
3432         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3433 }
3434
3435 void Render_Init(void)
3436 {
3437         gl_backend_init();
3438         R_Textures_Init();
3439         GL_Main_Init();
3440         Font_Init();
3441         GL_Draw_Init();
3442         R_Shadow_Init();
3443         R_Sky_Init();
3444         GL_Surf_Init();
3445         Sbar_Init();
3446         R_Particles_Init();
3447         R_Explosion_Init();
3448         R_LightningBeams_Init();
3449         Mod_RenderInit();
3450 }
3451
3452 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3453 {
3454         int i;
3455         mplane_t *p;
3456         if (r_trippy.integer)
3457                 return false;
3458         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3459         {
3460                 p = r_refdef.view.frustum + i;
3461                 switch(p->signbits)
3462                 {
3463                 default:
3464                 case 0:
3465                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3466                                 return true;
3467                         break;
3468                 case 1:
3469                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3470                                 return true;
3471                         break;
3472                 case 2:
3473                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3474                                 return true;
3475                         break;
3476                 case 3:
3477                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3478                                 return true;
3479                         break;
3480                 case 4:
3481                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3482                                 return true;
3483                         break;
3484                 case 5:
3485                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3486                                 return true;
3487                         break;
3488                 case 6:
3489                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3490                                 return true;
3491                         break;
3492                 case 7:
3493                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3494                                 return true;
3495                         break;
3496                 }
3497         }
3498         return false;
3499 }
3500
3501 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3502 {
3503         int i;
3504         const mplane_t *p;
3505         if (r_trippy.integer)
3506                 return false;
3507         for (i = 0;i < numplanes;i++)
3508         {
3509                 p = planes + i;
3510                 switch(p->signbits)
3511                 {
3512                 default:
3513                 case 0:
3514                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3515                                 return true;
3516                         break;
3517                 case 1:
3518                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3519                                 return true;
3520                         break;
3521                 case 2:
3522                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3523                                 return true;
3524                         break;
3525                 case 3:
3526                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3527                                 return true;
3528                         break;
3529                 case 4:
3530                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3531                                 return true;
3532                         break;
3533                 case 5:
3534                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3535                                 return true;
3536                         break;
3537                 case 6:
3538                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3539                                 return true;
3540                         break;
3541                 case 7:
3542                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3543                                 return true;
3544                         break;
3545                 }
3546         }
3547         return false;
3548 }
3549
3550 //==================================================================================
3551
3552 // LadyHavoc: this stores temporary data used within the same frame
3553
3554 typedef struct r_framedata_mem_s
3555 {
3556         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3557         size_t size; // how much usable space
3558         size_t current; // how much space in use
3559         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3560         size_t wantedsize; // how much space was allocated
3561         unsigned char *data; // start of real data (16byte aligned)
3562 }
3563 r_framedata_mem_t;
3564
3565 static r_framedata_mem_t *r_framedata_mem;
3566
3567 void R_FrameData_Reset(void)
3568 {
3569         while (r_framedata_mem)
3570         {
3571                 r_framedata_mem_t *next = r_framedata_mem->purge;
3572                 Mem_Free(r_framedata_mem);
3573                 r_framedata_mem = next;
3574         }
3575 }
3576
3577 static void R_FrameData_Resize(qbool mustgrow)
3578 {
3579         size_t wantedsize;
3580         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3581         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3582         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3583         {
3584                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3585                 newmem->wantedsize = wantedsize;
3586                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3587                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3588                 newmem->current = 0;
3589                 newmem->mark = 0;
3590                 newmem->purge = r_framedata_mem;
3591                 r_framedata_mem = newmem;
3592         }
3593 }
3594
3595 void R_FrameData_NewFrame(void)
3596 {
3597         R_FrameData_Resize(false);
3598         if (!r_framedata_mem)
3599                 return;
3600         // if we ran out of space on the last frame, free the old memory now
3601         while (r_framedata_mem->purge)
3602         {
3603                 // repeatedly remove the second item in the list, leaving only head
3604                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3605                 Mem_Free(r_framedata_mem->purge);
3606                 r_framedata_mem->purge = next;
3607         }
3608         // reset the current mem pointer
3609         r_framedata_mem->current = 0;
3610         r_framedata_mem->mark = 0;
3611 }
3612
3613 void *R_FrameData_Alloc(size_t size)
3614 {
3615         void *data;
3616         float newvalue;
3617
3618         // align to 16 byte boundary - the data pointer is already aligned, so we
3619         // only need to ensure the size of every allocation is also aligned
3620         size = (size + 15) & ~15;
3621
3622         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3623         {
3624                 // emergency - we ran out of space, allocate more memory
3625                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3626                 newvalue = r_framedatasize.value * 2.0f;
3627                 // 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
3628                 if (sizeof(size_t) >= 8)
3629                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3630                 else
3631                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3632                 // this might not be a growing it, but we'll allocate another buffer every time
3633                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3634                 R_FrameData_Resize(true);
3635         }
3636
3637         data = r_framedata_mem->data + r_framedata_mem->current;
3638         r_framedata_mem->current += size;
3639
3640         // count the usage for stats
3641         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3642         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3643
3644         return (void *)data;
3645 }
3646
3647 void *R_FrameData_Store(size_t size, void *data)
3648 {
3649         void *d = R_FrameData_Alloc(size);
3650         if (d && data)
3651                 memcpy(d, data, size);
3652         return d;
3653 }
3654
3655 void R_FrameData_SetMark(void)
3656 {
3657         if (!r_framedata_mem)
3658                 return;
3659         r_framedata_mem->mark = r_framedata_mem->current;
3660 }
3661
3662 void R_FrameData_ReturnToMark(void)
3663 {
3664         if (!r_framedata_mem)
3665                 return;
3666         r_framedata_mem->current = r_framedata_mem->mark;
3667 }
3668
3669 //==================================================================================
3670
3671 // avoid reusing the same buffer objects on consecutive frames
3672 #define R_BUFFERDATA_CYCLE 3
3673
3674 typedef struct r_bufferdata_buffer_s
3675 {
3676         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3677         size_t size; // how much usable space
3678         size_t current; // how much space in use
3679         r_meshbuffer_t *buffer; // the buffer itself
3680 }
3681 r_bufferdata_buffer_t;
3682
3683 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3684 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3685
3686 /// frees all dynamic buffers
3687 void R_BufferData_Reset(void)
3688 {
3689         int cycle, type;
3690         r_bufferdata_buffer_t **p, *mem;
3691         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3692         {
3693                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3694                 {
3695                         // free all buffers
3696                         p = &r_bufferdata_buffer[cycle][type];
3697                         while (*p)
3698                         {
3699                                 mem = *p;
3700                                 *p = (*p)->purge;
3701                                 if (mem->buffer)
3702                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3703                                 Mem_Free(mem);
3704                         }
3705                 }
3706         }
3707 }
3708
3709 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3710 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3711 {
3712         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3713         size_t size;
3714         float newvalue = r_buffermegs[type].value;
3715
3716         // increase the cvar if we have to (but only if we already have a mem)
3717         if (mustgrow && mem)
3718                 newvalue *= 2.0f;
3719         newvalue = bound(0.25f, newvalue, 256.0f);
3720         while (newvalue * 1024*1024 < minsize)
3721                 newvalue *= 2.0f;
3722
3723         // clamp the cvar to valid range
3724         newvalue = bound(0.25f, newvalue, 256.0f);
3725         if (r_buffermegs[type].value != newvalue)
3726                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3727
3728         // calculate size in bytes
3729         size = (size_t)(newvalue * 1024*1024);
3730         size = bound(131072, size, 256*1024*1024);
3731
3732         // allocate a new buffer if the size is different (purge old one later)
3733         // or if we were told we must grow the buffer
3734         if (!mem || mem->size != size || mustgrow)
3735         {
3736                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3737                 mem->size = size;
3738                 mem->current = 0;
3739                 if (type == R_BUFFERDATA_VERTEX)
3740                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3741                 else if (type == R_BUFFERDATA_INDEX16)
3742                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3743                 else if (type == R_BUFFERDATA_INDEX32)
3744                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3745                 else if (type == R_BUFFERDATA_UNIFORM)
3746                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3747                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3748                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3749         }
3750 }
3751
3752 void R_BufferData_NewFrame(void)
3753 {
3754         int type;
3755         r_bufferdata_buffer_t **p, *mem;
3756         // cycle to the next frame's buffers
3757         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3758         // if we ran out of space on the last time we used these buffers, free the old memory now
3759         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3760         {
3761                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3762                 {
3763                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3764                         // free all but the head buffer, this is how we recycle obsolete
3765                         // buffers after they are no longer in use
3766                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3767                         while (*p)
3768                         {
3769                                 mem = *p;
3770                                 *p = (*p)->purge;
3771                                 if (mem->buffer)
3772                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3773                                 Mem_Free(mem);
3774                         }
3775                         // reset the current offset
3776                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3777                 }
3778         }
3779 }
3780
3781 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3782 {
3783         r_bufferdata_buffer_t *mem;
3784         int offset = 0;
3785         int padsize;
3786
3787         *returnbufferoffset = 0;
3788
3789         // align size to a byte boundary appropriate for the buffer type, this
3790         // makes all allocations have aligned start offsets
3791         if (type == R_BUFFERDATA_UNIFORM)
3792                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3793         else
3794                 padsize = (datasize + 15) & ~15;
3795
3796         // if we ran out of space in this buffer we must allocate a new one
3797         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3798                 R_BufferData_Resize(type, true, padsize);
3799
3800         // if the resize did not give us enough memory, fail
3801         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)
3802                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3803
3804         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3805         offset = (int)mem->current;
3806         mem->current += padsize;
3807
3808         // upload the data to the buffer at the chosen offset
3809         if (offset == 0)
3810                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3811         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3812
3813         // count the usage for stats
3814         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3815         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3816
3817         // return the buffer offset
3818         *returnbufferoffset = offset;
3819
3820         return mem->buffer;
3821 }
3822
3823 //==================================================================================
3824
3825 // LadyHavoc: animcache originally written by Echon, rewritten since then
3826
3827 /**
3828  * Animation cache prevents re-generating mesh data for an animated model
3829  * multiple times in one frame for lighting, shadowing, reflections, etc.
3830  */
3831
3832 void R_AnimCache_Free(void)
3833 {
3834 }
3835
3836 void R_AnimCache_ClearCache(void)
3837 {
3838         int i;
3839         entity_render_t *ent;
3840
3841         for (i = 0;i < r_refdef.scene.numentities;i++)
3842         {
3843                 ent = r_refdef.scene.entities[i];
3844                 ent->animcache_vertex3f = NULL;
3845                 ent->animcache_vertex3f_vertexbuffer = NULL;
3846                 ent->animcache_vertex3f_bufferoffset = 0;
3847                 ent->animcache_normal3f = NULL;
3848                 ent->animcache_normal3f_vertexbuffer = NULL;
3849                 ent->animcache_normal3f_bufferoffset = 0;
3850                 ent->animcache_svector3f = NULL;
3851                 ent->animcache_svector3f_vertexbuffer = NULL;
3852                 ent->animcache_svector3f_bufferoffset = 0;
3853                 ent->animcache_tvector3f = NULL;
3854                 ent->animcache_tvector3f_vertexbuffer = NULL;
3855                 ent->animcache_tvector3f_bufferoffset = 0;
3856                 ent->animcache_skeletaltransform3x4 = NULL;
3857                 ent->animcache_skeletaltransform3x4buffer = NULL;
3858                 ent->animcache_skeletaltransform3x4offset = 0;
3859                 ent->animcache_skeletaltransform3x4size = 0;
3860         }
3861 }
3862
3863 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3864 {
3865         model_t *model = ent->model;
3866         int numvertices;
3867
3868         // see if this ent is worth caching
3869         if (!model || !model->Draw || !model->AnimateVertices)
3870                 return false;
3871         // nothing to cache if it contains no animations and has no skeleton
3872         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3873                 return false;
3874         // see if it is already cached for gpuskeletal
3875         if (ent->animcache_skeletaltransform3x4)
3876                 return false;
3877         // see if it is already cached as a mesh
3878         if (ent->animcache_vertex3f)
3879         {
3880                 // check if we need to add normals or tangents
3881                 if (ent->animcache_normal3f)
3882                         wantnormals = false;
3883                 if (ent->animcache_svector3f)
3884                         wanttangents = false;
3885                 if (!wantnormals && !wanttangents)
3886                         return false;
3887         }
3888
3889         // check which kind of cache we need to generate
3890         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3891         {
3892                 // cache the skeleton so the vertex shader can use it
3893                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3894                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3895                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3896                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3897                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3898                 // note: this can fail if the buffer is at the grow limit
3899                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3900                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3901         }
3902         else if (ent->animcache_vertex3f)
3903         {
3904                 // mesh was already cached but we may need to add normals/tangents
3905                 // (this only happens with multiple views, reflections, cameras, etc)
3906                 if (wantnormals || wanttangents)
3907                 {
3908                         numvertices = model->surfmesh.num_vertices;
3909                         if (wantnormals)
3910                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3911                         if (wanttangents)
3912                         {
3913                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3914                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3915                         }
3916                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3917                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3918                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3919                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3920                 }
3921         }
3922         else
3923         {
3924                 // generate mesh cache
3925                 numvertices = model->surfmesh.num_vertices;
3926                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3927                 if (wantnormals)
3928                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3929                 if (wanttangents)
3930                 {
3931                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3932                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3933                 }
3934                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3935                 if (wantnormals || wanttangents)
3936                 {
3937                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3938                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3939                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3940                 }
3941                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3942                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3943                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3944         }
3945         return true;
3946 }
3947
3948 void R_AnimCache_CacheVisibleEntities(void)
3949 {
3950         int i;
3951
3952         // TODO: thread this
3953         // NOTE: R_PrepareRTLights() also caches entities
3954
3955         for (i = 0;i < r_refdef.scene.numentities;i++)
3956                 if (r_refdef.viewcache.entityvisible[i])
3957                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3958 }
3959
3960 //==================================================================================
3961
3962 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)
3963 {
3964         long unsigned int i;
3965         int j;
3966         vec3_t eyemins, eyemaxs;
3967         vec3_t boxmins, boxmaxs;
3968         vec3_t padmins, padmaxs;
3969         vec3_t start;
3970         vec3_t end;
3971         model_t *model = r_refdef.scene.worldmodel;
3972         static vec3_t positions[] = {
3973                 { 0.5f, 0.5f, 0.5f },
3974                 { 0.0f, 0.0f, 0.0f },
3975                 { 0.0f, 0.0f, 1.0f },
3976                 { 0.0f, 1.0f, 0.0f },
3977                 { 0.0f, 1.0f, 1.0f },
3978                 { 1.0f, 0.0f, 0.0f },
3979                 { 1.0f, 0.0f, 1.0f },
3980                 { 1.0f, 1.0f, 0.0f },
3981                 { 1.0f, 1.0f, 1.0f },
3982         };
3983
3984         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3985         if (numsamples < 0)
3986                 return true;
3987
3988         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3989         if (!r_refdef.view.usevieworiginculling)
3990                 return true;
3991
3992         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3993                 return true;
3994
3995         // expand the eye box a little
3996         eyemins[0] = eye[0] - eyejitter;
3997         eyemaxs[0] = eye[0] + eyejitter;
3998         eyemins[1] = eye[1] - eyejitter;
3999         eyemaxs[1] = eye[1] + eyejitter;
4000         eyemins[2] = eye[2] - eyejitter;
4001         eyemaxs[2] = eye[2] + eyejitter;
4002         // expand the box a little
4003         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4004         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4005         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4006         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4007         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4008         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4009         // make an even larger box for the acceptable area
4010         padmins[0] = boxmins[0] - pad;
4011         padmaxs[0] = boxmaxs[0] + pad;
4012         padmins[1] = boxmins[1] - pad;
4013         padmaxs[1] = boxmaxs[1] + pad;
4014         padmins[2] = boxmins[2] - pad;
4015         padmaxs[2] = boxmaxs[2] + pad;
4016
4017         // return true if eye overlaps enlarged box
4018         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4019                 return true;
4020
4021         // try specific positions in the box first - note that these can be cached
4022         if (r_cullentities_trace_entityocclusion.integer)
4023         {
4024                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4025                 {
4026                         trace_t trace;
4027                         VectorCopy(eye, start);
4028                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4029                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4030                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4031                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4032                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4033                         // not picky - if the trace ended anywhere in the box we're good
4034                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4035                                 return true;
4036                 }
4037         }
4038         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4039                 return true;
4040
4041         // try various random positions
4042         for (j = 0; j < numsamples; j++)
4043         {
4044                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4045                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4046                 if (r_cullentities_trace_entityocclusion.integer)
4047                 {
4048                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4049                         // not picky - if the trace ended anywhere in the box we're good
4050                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4051                                 return true;
4052                 }
4053                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4054                         return true;
4055         }
4056
4057         return false;
4058 }
4059
4060
4061 static void R_View_UpdateEntityVisible (void)
4062 {
4063         int i;
4064         int renderimask;
4065         int samples;
4066         entity_render_t *ent;
4067
4068         if (r_refdef.envmap || r_fb.water.hideplayer)
4069                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4070         else if (chase_active.integer || r_fb.water.renderingscene)
4071                 renderimask = RENDER_VIEWMODEL;
4072         else
4073                 renderimask = RENDER_EXTERIORMODEL;
4074         if (!r_drawviewmodel.integer)
4075                 renderimask |= RENDER_VIEWMODEL;
4076         if (!r_drawexteriormodel.integer)
4077                 renderimask |= RENDER_EXTERIORMODEL;
4078         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4079         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4080         {
4081                 // worldmodel can check visibility
4082                 for (i = 0;i < r_refdef.scene.numentities;i++)
4083                 {
4084                         ent = r_refdef.scene.entities[i];
4085                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4086                         {
4087                                 r_refdef.viewcache.entityvisible[i] = false;
4088                                 continue;
4089                         }
4090                         if (!(ent->flags & renderimask))
4091                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4092                         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))
4093                                 r_refdef.viewcache.entityvisible[i] = true;
4094                 }
4095         }
4096         else
4097         {
4098                 // no worldmodel or it can't check visibility
4099                 for (i = 0;i < r_refdef.scene.numentities;i++)
4100                 {
4101                         ent = r_refdef.scene.entities[i];
4102                         if (!(ent->flags & renderimask))
4103                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4104                                 r_refdef.viewcache.entityvisible[i] = true;
4105                 }
4106         }
4107         if (r_cullentities_trace.integer)
4108         {
4109                 for (i = 0;i < r_refdef.scene.numentities;i++)
4110                 {
4111                         if (!r_refdef.viewcache.entityvisible[i])
4112                                 continue;
4113                         ent = r_refdef.scene.entities[i];
4114                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4115                         {
4116                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4117                                 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))
4118                                         ent->last_trace_visibility = host.realtime;
4119                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4120                                         r_refdef.viewcache.entityvisible[i] = 0;
4121                         }
4122                 }
4123         }
4124 }
4125
4126 /// only used if skyrendermasked, and normally returns false
4127 static int R_DrawBrushModelsSky (void)
4128 {
4129         int i, sky;
4130         entity_render_t *ent;
4131
4132         sky = false;
4133         for (i = 0;i < r_refdef.scene.numentities;i++)
4134         {
4135                 if (!r_refdef.viewcache.entityvisible[i])
4136                         continue;
4137                 ent = r_refdef.scene.entities[i];
4138                 if (!ent->model || !ent->model->DrawSky)
4139                         continue;
4140                 ent->model->DrawSky(ent);
4141                 sky = true;
4142         }
4143         return sky;
4144 }
4145
4146 static void R_DrawNoModel(entity_render_t *ent);
4147 static void R_DrawModels(void)
4148 {
4149         int i;
4150         entity_render_t *ent;
4151
4152         for (i = 0;i < r_refdef.scene.numentities;i++)
4153         {
4154                 if (!r_refdef.viewcache.entityvisible[i])
4155                         continue;
4156                 ent = r_refdef.scene.entities[i];
4157                 r_refdef.stats[r_stat_entities]++;
4158
4159                 if (ent->model && ent->model->Draw != NULL)
4160                         ent->model->Draw(ent);
4161                 else
4162                         R_DrawNoModel(ent);
4163         }
4164 }
4165
4166 static void R_DrawModelsDepth(void)
4167 {
4168         int i;
4169         entity_render_t *ent;
4170
4171         for (i = 0;i < r_refdef.scene.numentities;i++)
4172         {
4173                 if (!r_refdef.viewcache.entityvisible[i])
4174                         continue;
4175                 ent = r_refdef.scene.entities[i];
4176                 if (ent->model && ent->model->DrawDepth != NULL)
4177                         ent->model->DrawDepth(ent);
4178         }
4179 }
4180
4181 static void R_DrawModelsDebug(void)
4182 {
4183         int i;
4184         entity_render_t *ent;
4185
4186         for (i = 0;i < r_refdef.scene.numentities;i++)
4187         {
4188                 if (!r_refdef.viewcache.entityvisible[i])
4189                         continue;
4190                 ent = r_refdef.scene.entities[i];
4191                 if (ent->model && ent->model->DrawDebug != NULL)
4192                         ent->model->DrawDebug(ent);
4193         }
4194 }
4195
4196 static void R_DrawModelsAddWaterPlanes(void)
4197 {
4198         int i;
4199         entity_render_t *ent;
4200
4201         for (i = 0;i < r_refdef.scene.numentities;i++)
4202         {
4203                 if (!r_refdef.viewcache.entityvisible[i])
4204                         continue;
4205                 ent = r_refdef.scene.entities[i];
4206                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4207                         ent->model->DrawAddWaterPlanes(ent);
4208         }
4209 }
4210
4211 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}};
4212
4213 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4214 {
4215         if (r_hdr_irisadaptation.integer)
4216         {
4217                 vec3_t p;
4218                 vec3_t ambient;
4219                 vec3_t diffuse;
4220                 vec3_t diffusenormal;
4221                 vec3_t forward;
4222                 vec_t brightness = 0.0f;
4223                 vec_t goal;
4224                 vec_t current;
4225                 vec_t d;
4226                 int c;
4227                 VectorCopy(r_refdef.view.forward, forward);
4228                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4229                 {
4230                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4231                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4232                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4233                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4234                         d = DotProduct(forward, diffusenormal);
4235                         brightness += VectorLength(ambient);
4236                         if (d > 0)
4237                                 brightness += d * VectorLength(diffuse);
4238                 }
4239                 brightness *= 1.0f / c;
4240                 brightness += 0.00001f; // make sure it's never zero
4241                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4242                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4243                 current = r_hdr_irisadaptation_value.value;
4244                 if (current < goal)
4245                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4246                 else if (current > goal)
4247                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4248                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4249                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4250         }
4251         else if (r_hdr_irisadaptation_value.value != 1.0f)
4252                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4253 }
4254
4255 extern cvar_t r_lockvisibility;
4256 extern cvar_t r_lockpvs;
4257
4258 static void R_View_SetFrustum(const int *scissor)
4259 {
4260         int i;
4261         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4262         vec3_t forward, left, up, origin, v;
4263         if(r_lockvisibility.integer)
4264                 return;
4265         if(scissor)
4266         {
4267                 // flipped x coordinates (because x points left here)
4268                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4269                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4270                 // non-flipped y coordinates
4271                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4272                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4273         }
4274
4275         // we can't trust r_refdef.view.forward and friends in reflected scenes
4276         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4277
4278 #if 0
4279         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4280         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4281         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4282         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4283         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4284         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4285         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4286         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4287         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4288         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4289         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4290         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4291 #endif
4292
4293 #if 0
4294         zNear = r_refdef.nearclip;
4295         nudge = 1.0 - 1.0 / (1<<23);
4296         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4297         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4298         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4299         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4300         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4301         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4302         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4303         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4304 #endif
4305
4306
4307
4308 #if 0
4309         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4310         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4311         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4312         r_refdef.view.frustum[0].dist = m[15] - m[12];
4313
4314         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4315         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4316         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4317         r_refdef.view.frustum[1].dist = m[15] + m[12];
4318
4319         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4320         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4321         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4322         r_refdef.view.frustum[2].dist = m[15] - m[13];
4323
4324         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4325         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4326         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4327         r_refdef.view.frustum[3].dist = m[15] + m[13];
4328
4329         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4330         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4331         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4332         r_refdef.view.frustum[4].dist = m[15] - m[14];
4333
4334         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4335         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4336         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4337         r_refdef.view.frustum[5].dist = m[15] + m[14];
4338 #endif
4339
4340         if (r_refdef.view.useperspective)
4341         {
4342                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4343                 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]);
4344                 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]);
4345                 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]);
4346                 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]);
4347
4348                 // then the normals from the corners relative to origin
4349                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4350                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4351                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4352                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4353
4354                 // in a NORMAL view, forward cross left == up
4355                 // in a REFLECTED view, forward cross left == down
4356                 // so our cross products above need to be adjusted for a left handed coordinate system
4357                 CrossProduct(forward, left, v);
4358                 if(DotProduct(v, up) < 0)
4359                 {
4360                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4361                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4362                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4363                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4364                 }
4365
4366                 // Leaving those out was a mistake, those were in the old code, and they
4367                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4368                 // I couldn't reproduce it after adding those normalizations. --blub
4369                 VectorNormalize(r_refdef.view.frustum[0].normal);
4370                 VectorNormalize(r_refdef.view.frustum[1].normal);
4371                 VectorNormalize(r_refdef.view.frustum[2].normal);
4372                 VectorNormalize(r_refdef.view.frustum[3].normal);
4373
4374                 // make the corners absolute
4375                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4376                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4377                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4378                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4379
4380                 // one more normal
4381                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4382
4383                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4384                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4385                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4386                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4387                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4388         }
4389         else
4390         {
4391                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4392                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4393                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4394                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4395                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4396                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4397                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4398                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4399                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4400                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4401         }
4402         r_refdef.view.numfrustumplanes = 5;
4403
4404         if (r_refdef.view.useclipplane)
4405         {
4406                 r_refdef.view.numfrustumplanes = 6;
4407                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4408         }
4409
4410         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4411                 PlaneClassify(r_refdef.view.frustum + i);
4412
4413         // LadyHavoc: note to all quake engine coders, Quake had a special case
4414         // for 90 degrees which assumed a square view (wrong), so I removed it,
4415         // Quake2 has it disabled as well.
4416
4417         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4418         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4419         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4420         //PlaneClassify(&frustum[0]);
4421
4422         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4423         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4424         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4425         //PlaneClassify(&frustum[1]);
4426
4427         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4428         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4429         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4430         //PlaneClassify(&frustum[2]);
4431
4432         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4433         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4434         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4435         //PlaneClassify(&frustum[3]);
4436
4437         // nearclip plane
4438         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4439         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4440         //PlaneClassify(&frustum[4]);
4441 }
4442
4443 static void R_View_UpdateWithScissor(const int *myscissor)
4444 {
4445         R_Main_ResizeViewCache();
4446         R_View_SetFrustum(myscissor);
4447         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4448         R_View_UpdateEntityVisible();
4449 }
4450
4451 static void R_View_Update(void)
4452 {
4453         R_Main_ResizeViewCache();
4454         R_View_SetFrustum(NULL);
4455         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4456         R_View_UpdateEntityVisible();
4457 }
4458
4459 float viewscalefpsadjusted = 1.0f;
4460
4461 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4462 {
4463         const float *customclipplane = NULL;
4464         float plane[4];
4465         int /*rtwidth,*/ rtheight;
4466         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4467         {
4468                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4469                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4470                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4471                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4472                         dist = r_refdef.view.clipplane.dist;
4473                 plane[0] = r_refdef.view.clipplane.normal[0];
4474                 plane[1] = r_refdef.view.clipplane.normal[1];
4475                 plane[2] = r_refdef.view.clipplane.normal[2];
4476                 plane[3] = -dist;
4477                 customclipplane = plane;
4478         }
4479
4480         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4481         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4482
4483         if (!r_refdef.view.useperspective)
4484                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4485         else if (vid.stencil && r_useinfinitefarclip.integer)
4486                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4487         else
4488                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4489         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4490         R_SetViewport(&r_refdef.view.viewport);
4491 }
4492
4493 void R_EntityMatrix(const matrix4x4_t *matrix)
4494 {
4495         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4496         {
4497                 gl_modelmatrixchanged = false;
4498                 gl_modelmatrix = *matrix;
4499                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4500                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4501                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4502                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4503                 CHECKGLERROR
4504                 switch(vid.renderpath)
4505                 {
4506                 case RENDERPATH_GL32:
4507                 case RENDERPATH_GLES2:
4508                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4509                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4510                         break;
4511                 }
4512         }
4513 }
4514
4515 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4516 {
4517         r_viewport_t viewport;
4518
4519         CHECKGLERROR
4520
4521         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4522         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4523         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4524         R_SetViewport(&viewport);
4525         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4526         GL_Color(1, 1, 1, 1);
4527         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4528         GL_BlendFunc(GL_ONE, GL_ZERO);
4529         GL_ScissorTest(false);
4530         GL_DepthMask(false);
4531         GL_DepthRange(0, 1);
4532         GL_DepthTest(false);
4533         GL_DepthFunc(GL_LEQUAL);
4534         R_EntityMatrix(&identitymatrix);
4535         R_Mesh_ResetTextureState();
4536         GL_PolygonOffset(0, 0);
4537         switch(vid.renderpath)
4538         {
4539         case RENDERPATH_GL32:
4540         case RENDERPATH_GLES2:
4541                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4542                 break;
4543         }
4544         GL_CullFace(GL_NONE);
4545
4546         CHECKGLERROR
4547 }
4548
4549 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4550 {
4551         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4552 }
4553
4554 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4555 {
4556         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4557         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4558         GL_Color(1, 1, 1, 1);
4559         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4560         GL_BlendFunc(GL_ONE, GL_ZERO);
4561         GL_ScissorTest(true);
4562         GL_DepthMask(true);
4563         GL_DepthRange(0, 1);
4564         GL_DepthTest(true);
4565         GL_DepthFunc(GL_LEQUAL);
4566         R_EntityMatrix(&identitymatrix);
4567         R_Mesh_ResetTextureState();
4568         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4569         switch(vid.renderpath)
4570         {
4571         case RENDERPATH_GL32:
4572         case RENDERPATH_GLES2:
4573                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4574                 break;
4575         }
4576         GL_CullFace(r_refdef.view.cullface_back);
4577 }
4578
4579 /*
4580 ================
4581 R_RenderView_UpdateViewVectors
4582 ================
4583 */
4584 void R_RenderView_UpdateViewVectors(void)
4585 {
4586         // break apart the view matrix into vectors for various purposes
4587         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4588         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4589         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4590         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4591         // make an inverted copy of the view matrix for tracking sprites
4592         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4593 }
4594
4595 void R_RenderTarget_FreeUnused(qbool force)
4596 {
4597         unsigned int i, j, end;
4598         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4599         for (i = 0; i < end; i++)
4600         {
4601                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4602                 // free resources for rendertargets that have not been used for a while
4603                 // (note: this check is run after the frame render, so any targets used
4604                 // this frame will not be affected even at low framerates)
4605                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4606                 {
4607                         if (r->fbo)
4608                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4609                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4610                                 if (r->colortexture[j])
4611                                         R_FreeTexture(r->colortexture[j]);
4612                         if (r->depthtexture)
4613                                 R_FreeTexture(r->depthtexture);
4614                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4615                 }
4616         }
4617 }
4618
4619 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4620 {
4621         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4622         x1 = x * iw;
4623         x2 = (x + w) * iw;
4624         y1 = (th - y) * ih;
4625         y2 = (th - y - h) * ih;
4626         texcoord2f[0] = x1;
4627         texcoord2f[2] = x2;
4628         texcoord2f[4] = x2;
4629         texcoord2f[6] = x1;
4630         texcoord2f[1] = y1;
4631         texcoord2f[3] = y1;
4632         texcoord2f[5] = y2;
4633         texcoord2f[7] = y2;
4634 }
4635
4636 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)
4637 {
4638         unsigned int i, j, end;
4639         r_rendertarget_t *r = NULL;
4640         char vabuf[256];
4641         // first try to reuse an existing slot if possible
4642         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4643         for (i = 0; i < end; i++)
4644         {
4645                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4646                 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)
4647                         break;
4648         }
4649         if (i == end)
4650         {
4651                 // no unused exact match found, so we have to make one in the first unused slot
4652                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4653                 r->texturewidth = texturewidth;
4654                 r->textureheight = textureheight;
4655                 r->colortextype[0] = colortextype0;
4656                 r->colortextype[1] = colortextype1;
4657                 r->colortextype[2] = colortextype2;
4658                 r->colortextype[3] = colortextype3;
4659                 r->depthtextype = depthtextype;
4660                 r->depthisrenderbuffer = depthisrenderbuffer;
4661                 for (j = 0; j < 4; j++)
4662                         if (r->colortextype[j])
4663                                 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);
4664                 if (r->depthtextype)
4665                 {
4666                         if (r->depthisrenderbuffer)
4667                                 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);
4668                         else
4669                                 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);
4670                 }
4671                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4672         }
4673         r_refdef.stats[r_stat_rendertargets_used]++;
4674         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4675         r->lastusetime = host.realtime;
4676         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4677         return r;
4678 }
4679
4680 static void R_Water_StartFrame(int viewwidth, int viewheight)
4681 {
4682         int waterwidth, waterheight;
4683
4684         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4685                 return;
4686
4687         // set waterwidth and waterheight to the water resolution that will be
4688         // used (often less than the screen resolution for faster rendering)
4689         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4690         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4691
4692         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4693                 waterwidth = waterheight = 0;
4694
4695         // set up variables that will be used in shader setup
4696         r_fb.water.waterwidth = waterwidth;
4697         r_fb.water.waterheight = waterheight;
4698         r_fb.water.texturewidth = waterwidth;
4699         r_fb.water.textureheight = waterheight;
4700         r_fb.water.camerawidth = waterwidth;
4701         r_fb.water.cameraheight = waterheight;
4702         r_fb.water.screenscale[0] = 0.5f;
4703         r_fb.water.screenscale[1] = 0.5f;
4704         r_fb.water.screencenter[0] = 0.5f;
4705         r_fb.water.screencenter[1] = 0.5f;
4706         r_fb.water.enabled = waterwidth != 0;
4707
4708         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4709         r_fb.water.numwaterplanes = 0;
4710 }
4711
4712 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4713 {
4714         int planeindex, bestplaneindex, vertexindex;
4715         vec3_t mins, maxs, normal, center, v, n;
4716         vec_t planescore, bestplanescore;
4717         mplane_t plane;
4718         r_waterstate_waterplane_t *p;
4719         texture_t *t = R_GetCurrentTexture(surface->texture);
4720
4721         rsurface.texture = t;
4722         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4723         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4724         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4725                 return;
4726         // average the vertex normals, find the surface bounds (after deformvertexes)
4727         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4728         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4729         VectorCopy(n, normal);
4730         VectorCopy(v, mins);
4731         VectorCopy(v, maxs);
4732         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4733         {
4734                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4735                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4736                 VectorAdd(normal, n, normal);
4737                 mins[0] = min(mins[0], v[0]);
4738                 mins[1] = min(mins[1], v[1]);
4739                 mins[2] = min(mins[2], v[2]);
4740                 maxs[0] = max(maxs[0], v[0]);
4741                 maxs[1] = max(maxs[1], v[1]);
4742                 maxs[2] = max(maxs[2], v[2]);
4743         }
4744         VectorNormalize(normal);
4745         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4746
4747         VectorCopy(normal, plane.normal);
4748         VectorNormalize(plane.normal);
4749         plane.dist = DotProduct(center, plane.normal);
4750         PlaneClassify(&plane);
4751         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4752         {
4753                 // skip backfaces (except if nocullface is set)
4754 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4755 //                      return;
4756                 VectorNegate(plane.normal, plane.normal);
4757                 plane.dist *= -1;
4758                 PlaneClassify(&plane);
4759         }
4760
4761
4762         // find a matching plane if there is one
4763         bestplaneindex = -1;
4764         bestplanescore = 1048576.0f;
4765         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4766         {
4767                 if(p->camera_entity == t->camera_entity)
4768                 {
4769                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4770                         if (bestplaneindex < 0 || bestplanescore > planescore)
4771                         {
4772                                 bestplaneindex = planeindex;
4773                                 bestplanescore = planescore;
4774                         }
4775                 }
4776         }
4777         planeindex = bestplaneindex;
4778
4779         // if this surface does not fit any known plane rendered this frame, add one
4780         if (planeindex < 0 || bestplanescore > 0.001f)
4781         {
4782                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4783                 {
4784                         // store the new plane
4785                         planeindex = r_fb.water.numwaterplanes++;
4786                         p = r_fb.water.waterplanes + planeindex;
4787                         p->plane = plane;
4788                         // clear materialflags and pvs
4789                         p->materialflags = 0;
4790                         p->pvsvalid = false;
4791                         p->camera_entity = t->camera_entity;
4792                         VectorCopy(mins, p->mins);
4793                         VectorCopy(maxs, p->maxs);
4794                 }
4795                 else
4796                 {
4797                         // We're totally screwed.
4798                         return;
4799                 }
4800         }
4801         else
4802         {
4803                 // merge mins/maxs when we're adding this surface to the plane
4804                 p = r_fb.water.waterplanes + planeindex;
4805                 p->mins[0] = min(p->mins[0], mins[0]);
4806                 p->mins[1] = min(p->mins[1], mins[1]);
4807                 p->mins[2] = min(p->mins[2], mins[2]);
4808                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4809                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4810                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4811         }
4812         // merge this surface's materialflags into the waterplane
4813         p->materialflags |= t->currentmaterialflags;
4814         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4815         {
4816                 // merge this surface's PVS into the waterplane
4817                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4818                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4819                 {
4820                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4821                         p->pvsvalid = true;
4822                 }
4823         }
4824 }
4825
4826 extern cvar_t r_drawparticles;
4827 extern cvar_t r_drawdecals;
4828
4829 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4830 {
4831         int myscissor[4];
4832         r_refdef_view_t originalview;
4833         r_refdef_view_t myview;
4834         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;
4835         r_waterstate_waterplane_t *p;
4836         vec3_t visorigin;
4837         r_rendertarget_t *rt;
4838
4839         originalview = r_refdef.view;
4840
4841         // lowquality hack, temporarily shut down some cvars and restore afterwards
4842         qualityreduction = r_water_lowquality.integer;
4843         if (qualityreduction > 0)
4844         {
4845                 if (qualityreduction >= 1)
4846                 {
4847                         old_r_shadows = r_shadows.integer;
4848                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4849                         old_r_dlight = r_shadow_realtime_dlight.integer;
4850                         Cvar_SetValueQuick(&r_shadows, 0);
4851                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4852                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4853                 }
4854                 if (qualityreduction >= 2)
4855                 {
4856                         old_r_dynamic = r_dynamic.integer;
4857                         old_r_particles = r_drawparticles.integer;
4858                         old_r_decals = r_drawdecals.integer;
4859                         Cvar_SetValueQuick(&r_dynamic, 0);
4860                         Cvar_SetValueQuick(&r_drawparticles, 0);
4861                         Cvar_SetValueQuick(&r_drawdecals, 0);
4862                 }
4863         }
4864
4865         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4866         {
4867                 p->rt_reflection = NULL;
4868                 p->rt_refraction = NULL;
4869                 p->rt_camera = NULL;
4870         }
4871
4872         // render views
4873         r_refdef.view = originalview;
4874         r_refdef.view.showdebug = false;
4875         r_refdef.view.width = r_fb.water.waterwidth;
4876         r_refdef.view.height = r_fb.water.waterheight;
4877         r_refdef.view.useclipplane = true;
4878         myview = r_refdef.view;
4879         r_fb.water.renderingscene = true;
4880         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4881         {
4882                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4883                         continue;
4884
4885                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4886                 {
4887                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4888                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4889                                 goto error;
4890                         r_refdef.view = myview;
4891                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4892                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4893                         if(r_water_scissormode.integer)
4894                         {
4895                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4896                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4897                                 {
4898                                         p->rt_reflection = NULL;
4899                                         p->rt_refraction = NULL;
4900                                         p->rt_camera = NULL;
4901                                         continue;
4902                                 }
4903                         }
4904
4905                         r_refdef.view.clipplane = p->plane;
4906                         // reflected view origin may be in solid, so don't cull with it
4907                         r_refdef.view.usevieworiginculling = false;
4908                         // reverse the cullface settings for this render
4909                         r_refdef.view.cullface_front = GL_FRONT;
4910                         r_refdef.view.cullface_back = GL_BACK;
4911                         // combined pvs (based on what can be seen from each surface center)
4912                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4913                         {
4914                                 r_refdef.view.usecustompvs = true;
4915                                 if (p->pvsvalid)
4916                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4917                                 else
4918                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4919                         }
4920
4921                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4922                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4923                         GL_ScissorTest(false);
4924                         R_ClearScreen(r_refdef.fogenabled);
4925                         GL_ScissorTest(true);
4926                         if(r_water_scissormode.integer & 2)
4927                                 R_View_UpdateWithScissor(myscissor);
4928                         else
4929                                 R_View_Update();
4930                         R_AnimCache_CacheVisibleEntities();
4931                         if(r_water_scissormode.integer & 1)
4932                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4933                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4934
4935                         r_fb.water.hideplayer = false;
4936                         p->rt_reflection = rt;
4937                 }
4938
4939                 // render the normal view scene and copy into texture
4940                 // (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)
4941                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4942                 {
4943                         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);
4944                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4945                                 goto error;
4946                         r_refdef.view = myview;
4947                         if(r_water_scissormode.integer)
4948                         {
4949                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4950                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4951                                 {
4952                                         p->rt_reflection = NULL;
4953                                         p->rt_refraction = NULL;
4954                                         p->rt_camera = NULL;
4955                                         continue;
4956                                 }
4957                         }
4958
4959                         // combined pvs (based on what can be seen from each surface center)
4960                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4961                         {
4962                                 r_refdef.view.usecustompvs = true;
4963                                 if (p->pvsvalid)
4964                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4965                                 else
4966                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4967                         }
4968
4969                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4970
4971                         r_refdef.view.clipplane = p->plane;
4972                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4973                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4974
4975                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4976                         {
4977                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4978                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4979                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4980                                 R_RenderView_UpdateViewVectors();
4981                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4982                                 {
4983                                         r_refdef.view.usecustompvs = true;
4984                                         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);
4985                                 }
4986                         }
4987
4988                         PlaneClassify(&r_refdef.view.clipplane);
4989
4990                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4991                         GL_ScissorTest(false);
4992                         R_ClearScreen(r_refdef.fogenabled);
4993                         GL_ScissorTest(true);
4994                         if(r_water_scissormode.integer & 2)
4995                                 R_View_UpdateWithScissor(myscissor);
4996                         else
4997                                 R_View_Update();
4998                         R_AnimCache_CacheVisibleEntities();
4999                         if(r_water_scissormode.integer & 1)
5000                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5001                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5002
5003                         r_fb.water.hideplayer = false;
5004                         p->rt_refraction = rt;
5005                 }
5006                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5007                 {
5008                         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);
5009                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5010                                 goto error;
5011                         r_refdef.view = myview;
5012
5013                         r_refdef.view.clipplane = p->plane;
5014                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5015                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5016
5017                         r_refdef.view.width = r_fb.water.camerawidth;
5018                         r_refdef.view.height = r_fb.water.cameraheight;
5019                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5020                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5021                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5022                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5023
5024                         if(p->camera_entity)
5025                         {
5026                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5027                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5028                         }
5029
5030                         // note: all of the view is used for displaying... so
5031                         // there is no use in scissoring
5032
5033                         // reverse the cullface settings for this render
5034                         r_refdef.view.cullface_front = GL_FRONT;
5035                         r_refdef.view.cullface_back = GL_BACK;
5036                         // also reverse the view matrix
5037                         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
5038                         R_RenderView_UpdateViewVectors();
5039                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5040                         {
5041                                 r_refdef.view.usecustompvs = true;
5042                                 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);
5043                         }
5044                         
5045                         // camera needs no clipplane
5046                         r_refdef.view.useclipplane = false;
5047                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5048                         r_refdef.view.usevieworiginculling = false;
5049
5050                         PlaneClassify(&r_refdef.view.clipplane);
5051
5052                         r_fb.water.hideplayer = false;
5053
5054                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5055                         GL_ScissorTest(false);
5056                         R_ClearScreen(r_refdef.fogenabled);
5057                         GL_ScissorTest(true);
5058                         R_View_Update();
5059                         R_AnimCache_CacheVisibleEntities();
5060                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5061
5062                         r_fb.water.hideplayer = false;
5063                         p->rt_camera = rt;
5064                 }
5065
5066         }
5067         r_fb.water.renderingscene = false;
5068         r_refdef.view = originalview;
5069         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5070         R_View_Update();
5071         R_AnimCache_CacheVisibleEntities();
5072         goto finish;
5073 error:
5074         r_refdef.view = originalview;
5075         r_fb.water.renderingscene = false;
5076         Cvar_SetValueQuick(&r_water, 0);
5077         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5078 finish:
5079         // lowquality hack, restore cvars
5080         if (qualityreduction > 0)
5081         {
5082                 if (qualityreduction >= 1)
5083                 {
5084                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5085                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5086                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5087                 }
5088                 if (qualityreduction >= 2)
5089                 {
5090                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5091                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5092                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5093                 }
5094         }
5095 }
5096
5097 static void R_Bloom_StartFrame(void)
5098 {
5099         int screentexturewidth, screentextureheight;
5100         textype_t textype = TEXTYPE_COLORBUFFER;
5101         double scale;
5102
5103         // clear the pointers to rendertargets from last frame as they're stale
5104         r_fb.rt_screen = NULL;
5105         r_fb.rt_bloom = NULL;
5106
5107         switch (vid.renderpath)
5108         {
5109         case RENDERPATH_GL32:
5110                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5111                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5112                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5113                 break;
5114         case RENDERPATH_GLES2:
5115                 r_fb.usedepthtextures = false;
5116                 break;
5117         }
5118
5119         if (r_viewscale_fpsscaling.integer)
5120         {
5121                 double actualframetime;
5122                 double targetframetime;
5123                 double adjust;
5124                 actualframetime = r_refdef.lastdrawscreentime;
5125                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5126                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5127                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5128                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5129                 {
5130                         if (adjust > 0)
5131                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5132                         else
5133                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5134                 }
5135                 viewscalefpsadjusted += adjust;
5136                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5137         }
5138         else
5139                 viewscalefpsadjusted = 1.0f;
5140
5141         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5142         if (vid.samples)
5143                 scale *= sqrt(vid.samples); // supersampling
5144         scale = bound(0.03125f, scale, 4.0f);
5145         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5146         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5147         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5148         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5149
5150         // set bloomwidth and bloomheight to the bloom resolution that will be
5151         // used (often less than the screen resolution for faster rendering)
5152         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5153         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5154         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5155         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5156         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5157
5158         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))
5159         {
5160                 Cvar_SetValueQuick(&r_bloom, 0);
5161                 Cvar_SetValueQuick(&r_motionblur, 0);
5162                 Cvar_SetValueQuick(&r_damageblur, 0);
5163         }
5164         if (!r_bloom.integer)
5165                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5166
5167         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5168         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5169         {
5170                 if (r_fb.ghosttexture)
5171                         R_FreeTexture(r_fb.ghosttexture);
5172                 r_fb.ghosttexture = NULL;
5173
5174                 r_fb.screentexturewidth = screentexturewidth;
5175                 r_fb.screentextureheight = screentextureheight;
5176                 r_fb.textype = textype;
5177
5178                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5179                 {
5180                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5181                                 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);
5182                         r_fb.ghosttexture_valid = false;
5183                 }
5184         }
5185
5186         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5187
5188         r_refdef.view.clear = true;
5189 }
5190
5191 static void R_Bloom_MakeTexture(void)
5192 {
5193         int x, range, dir;
5194         float xoffset, yoffset, r, brighten;
5195         float colorscale = r_bloom_colorscale.value;
5196         r_viewport_t bloomviewport;
5197         r_rendertarget_t *prev, *cur;
5198         textype_t textype = r_fb.rt_screen->colortextype[0];
5199
5200         r_refdef.stats[r_stat_bloom]++;
5201
5202         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5203
5204         // scale down screen texture to the bloom texture size
5205         CHECKGLERROR
5206         prev = r_fb.rt_screen;
5207         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5208         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5209         R_SetViewport(&bloomviewport);
5210         GL_CullFace(GL_NONE);
5211         GL_DepthTest(false);
5212         GL_BlendFunc(GL_ONE, GL_ZERO);
5213         GL_Color(colorscale, colorscale, colorscale, 1);
5214         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5215         // TODO: do boxfilter scale-down in shader?
5216         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5217         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5218         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5219         // we now have a properly scaled bloom image
5220
5221         // multiply bloom image by itself as many times as desired to darken it
5222         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5223         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5224         {
5225                 prev = cur;
5226                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5227                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5228                 x *= 2;
5229                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5230                 if(x <= 2)
5231                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5232                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5233                 GL_Color(1,1,1,1); // no fix factor supported here
5234                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5235                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5236                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5237                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5238         }
5239         CHECKGLERROR
5240
5241         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5242         brighten = r_bloom_brighten.value;
5243         brighten = sqrt(brighten);
5244         if(range >= 1)
5245                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5246
5247         for (dir = 0;dir < 2;dir++)
5248         {
5249                 prev = cur;
5250                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5251                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5252                 // blend on at multiple vertical offsets to achieve a vertical blur
5253                 // TODO: do offset blends using GLSL
5254                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5255                 CHECKGLERROR
5256                 GL_BlendFunc(GL_ONE, GL_ZERO);
5257                 CHECKGLERROR
5258                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5259                 CHECKGLERROR
5260                 for (x = -range;x <= range;x++)
5261                 {
5262                         if (!dir){xoffset = 0;yoffset = x;}
5263                         else {xoffset = x;yoffset = 0;}
5264                         xoffset /= (float)prev->texturewidth;
5265                         yoffset /= (float)prev->textureheight;
5266                         // compute a texcoord array with the specified x and y offset
5267                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5268                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5269                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5270                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5271                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5272                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5273                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5274                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5275                         // this r value looks like a 'dot' particle, fading sharply to
5276                         // black at the edges
5277                         // (probably not realistic but looks good enough)
5278                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5279                         //r = brighten/(range*2+1);
5280                         r = brighten / (range * 2 + 1);
5281                         if(range >= 1)
5282                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5283                         if (r <= 0)
5284                                 continue;
5285                         CHECKGLERROR
5286                         GL_Color(r, r, r, 1);
5287                         CHECKGLERROR
5288                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5289                         CHECKGLERROR
5290                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5291                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5292                         CHECKGLERROR
5293                         GL_BlendFunc(GL_ONE, GL_ONE);
5294                         CHECKGLERROR
5295                 }
5296         }
5297
5298         // now we have the bloom image, so keep track of it
5299         r_fb.rt_bloom = cur;
5300 }
5301
5302 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5303 {
5304         uint64_t permutation;
5305         float uservecs[4][4];
5306         rtexture_t *viewtexture;
5307         rtexture_t *bloomtexture;
5308
5309         R_EntityMatrix(&identitymatrix);
5310
5311         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5312         {
5313                 // declare variables
5314                 float blur_factor, blur_mouseaccel, blur_velocity;
5315                 static float blur_average; 
5316                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5317
5318                 // set a goal for the factoring
5319                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5320                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5321                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5322                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5323                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5324                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5325
5326                 // from the goal, pick an averaged value between goal and last value
5327                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5328                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5329
5330                 // enforce minimum amount of blur 
5331                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5332
5333                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5334
5335                 // calculate values into a standard alpha
5336                 cl.motionbluralpha = 1 - exp(-
5337                                 (
5338                                         (r_motionblur.value * blur_factor / 80)
5339                                         +
5340                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5341                                 )
5342                                 /
5343                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5344                                 );
5345
5346                 // randomization for the blur value to combat persistent ghosting
5347                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5348                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5349
5350                 // apply the blur
5351                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5352                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5353                 {
5354                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5355                         GL_Color(1, 1, 1, cl.motionbluralpha);
5356                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5357                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5358                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5359                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5360                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5361                 }
5362
5363                 // updates old view angles for next pass
5364                 VectorCopy(cl.viewangles, blur_oldangles);
5365
5366                 // copy view into the ghost texture
5367                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5368                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5369                 r_fb.ghosttexture_valid = true;
5370         }
5371
5372         if (r_fb.bloomwidth)
5373         {
5374                 // make the bloom texture
5375                 R_Bloom_MakeTexture();
5376         }
5377
5378 #if _MSC_VER >= 1400
5379 #define sscanf sscanf_s
5380 #endif
5381         memset(uservecs, 0, sizeof(uservecs));
5382         if (r_glsl_postprocess_uservec1_enable.integer)
5383                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5384         if (r_glsl_postprocess_uservec2_enable.integer)
5385                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5386         if (r_glsl_postprocess_uservec3_enable.integer)
5387                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5388         if (r_glsl_postprocess_uservec4_enable.integer)
5389                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5390
5391         // render to the screen fbo
5392         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5393         GL_Color(1, 1, 1, 1);
5394         GL_BlendFunc(GL_ONE, GL_ZERO);
5395
5396         viewtexture = r_fb.rt_screen->colortexture[0];
5397         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5398
5399         if (r_rendertarget_debug.integer >= 0)
5400         {
5401                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5402                 if (rt && rt->colortexture[0])
5403                 {
5404                         viewtexture = rt->colortexture[0];
5405                         bloomtexture = NULL;
5406                 }
5407         }
5408
5409         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5410         switch(vid.renderpath)
5411         {
5412         case RENDERPATH_GL32:
5413         case RENDERPATH_GLES2:
5414                 permutation =
5415                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5416                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5417                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5418                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5419                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5420                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5421                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5422                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5423                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5424                 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]);
5425                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5426                 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]);
5427                 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]);
5428                 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]);
5429                 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]);
5430                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5431                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5432                 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);
5433                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5434                 break;
5435         }
5436         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5437         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5438 }
5439
5440 matrix4x4_t r_waterscrollmatrix;
5441
5442 void R_UpdateFog(void)
5443 {
5444         // Nehahra fog
5445         if (gamemode == GAME_NEHAHRA)
5446         {
5447                 if (gl_fogenable.integer)
5448                 {
5449                         r_refdef.oldgl_fogenable = true;
5450                         r_refdef.fog_density = gl_fogdensity.value;
5451                         r_refdef.fog_red = gl_fogred.value;
5452                         r_refdef.fog_green = gl_foggreen.value;
5453                         r_refdef.fog_blue = gl_fogblue.value;
5454                         r_refdef.fog_alpha = 1;
5455                         r_refdef.fog_start = 0;
5456                         r_refdef.fog_end = gl_skyclip.value;
5457                         r_refdef.fog_height = 1<<30;
5458                         r_refdef.fog_fadedepth = 128;
5459                 }
5460                 else if (r_refdef.oldgl_fogenable)
5461                 {
5462                         r_refdef.oldgl_fogenable = false;
5463                         r_refdef.fog_density = 0;
5464                         r_refdef.fog_red = 0;
5465                         r_refdef.fog_green = 0;
5466                         r_refdef.fog_blue = 0;
5467                         r_refdef.fog_alpha = 0;
5468                         r_refdef.fog_start = 0;
5469                         r_refdef.fog_end = 0;
5470                         r_refdef.fog_height = 1<<30;
5471                         r_refdef.fog_fadedepth = 128;
5472                 }
5473         }
5474
5475         // fog parms
5476         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5477         r_refdef.fog_start = max(0, r_refdef.fog_start);
5478         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5479
5480         if (r_refdef.fog_density && r_drawfog.integer)
5481         {
5482                 r_refdef.fogenabled = true;
5483                 // this is the point where the fog reaches 0.9986 alpha, which we
5484                 // consider a good enough cutoff point for the texture
5485                 // (0.9986 * 256 == 255.6)
5486                 if (r_fog_exp2.integer)
5487                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5488                 else
5489                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5490                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5491                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5492                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5493                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5494                         R_BuildFogHeightTexture();
5495                 // fog color was already set
5496                 // update the fog texture
5497                 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)
5498                         R_BuildFogTexture();
5499                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5500                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5501         }
5502         else
5503                 r_refdef.fogenabled = false;
5504
5505         // fog color
5506         if (r_refdef.fog_density)
5507         {
5508                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5509                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5510                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5511
5512                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5513                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5514                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5515                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5516
5517                 {
5518                         vec3_t fogvec;
5519                         VectorCopy(r_refdef.fogcolor, fogvec);
5520                         //   color.rgb *= ContrastBoost * SceneBrightness;
5521                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5522                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5523                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5524                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5525                 }
5526         }
5527 }
5528
5529 void R_UpdateVariables(void)
5530 {
5531         R_Textures_Frame();
5532
5533         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5534
5535         r_refdef.farclip = r_farclip_base.value;
5536         if (r_refdef.scene.worldmodel)
5537                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5538         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5539
5540         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5541                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5542         r_refdef.polygonfactor = 0;
5543         r_refdef.polygonoffset = 0;
5544
5545         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5546         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5547         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5548         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5549         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5550         if (r_refdef.scene.worldmodel)
5551         {
5552                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5553         }
5554         if (r_showsurfaces.integer)
5555         {
5556                 r_refdef.scene.rtworld = false;
5557                 r_refdef.scene.rtworldshadows = false;
5558                 r_refdef.scene.rtdlight = false;
5559                 r_refdef.scene.rtdlightshadows = false;
5560                 r_refdef.scene.lightmapintensity = 0;
5561         }
5562
5563         r_gpuskeletal = false;
5564         switch(vid.renderpath)
5565         {
5566         case RENDERPATH_GL32:
5567                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5568         case RENDERPATH_GLES2:
5569                 if(!vid_gammatables_trivial)
5570                 {
5571                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5572                         {
5573                                 // build GLSL gamma texture
5574 #define RAMPWIDTH 256
5575                                 unsigned short ramp[RAMPWIDTH * 3];
5576                                 unsigned char rampbgr[RAMPWIDTH][4];
5577                                 int i;
5578
5579                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5580
5581                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5582                                 for(i = 0; i < RAMPWIDTH; ++i)
5583                                 {
5584                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5585                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5586                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5587                                         rampbgr[i][3] = 0;
5588                                 }
5589                                 if (r_texture_gammaramps)
5590                                 {
5591                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5592                                 }
5593                                 else
5594                                 {
5595                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5596                                 }
5597                         }
5598                 }
5599                 else
5600                 {
5601                         // remove GLSL gamma texture
5602                 }
5603                 break;
5604         }
5605 }
5606
5607 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5608 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5609 /*
5610 ================
5611 R_SelectScene
5612 ================
5613 */
5614 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5615         if( scenetype != r_currentscenetype ) {
5616                 // store the old scenetype
5617                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5618                 r_currentscenetype = scenetype;
5619                 // move in the new scene
5620                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5621         }
5622 }
5623
5624 /*
5625 ================
5626 R_GetScenePointer
5627 ================
5628 */
5629 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5630 {
5631         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5632         if( scenetype == r_currentscenetype ) {
5633                 return &r_refdef.scene;
5634         } else {
5635                 return &r_scenes_store[ scenetype ];
5636         }
5637 }
5638
5639 static int R_SortEntities_Compare(const void *ap, const void *bp)
5640 {
5641         const entity_render_t *a = *(const entity_render_t **)ap;
5642         const entity_render_t *b = *(const entity_render_t **)bp;
5643
5644         // 1. compare model
5645         if(a->model < b->model)
5646                 return -1;
5647         if(a->model > b->model)
5648                 return +1;
5649
5650         // 2. compare skin
5651         // TODO possibly calculate the REAL skinnum here first using
5652         // skinscenes?
5653         if(a->skinnum < b->skinnum)
5654                 return -1;
5655         if(a->skinnum > b->skinnum)
5656                 return +1;
5657
5658         // everything we compared is equal
5659         return 0;
5660 }
5661 static void R_SortEntities(void)
5662 {
5663         // below or equal 2 ents, sorting never gains anything
5664         if(r_refdef.scene.numentities <= 2)
5665                 return;
5666         // sort
5667         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5668 }
5669
5670 /*
5671 ================
5672 R_RenderView
5673 ================
5674 */
5675 extern cvar_t r_shadow_bouncegrid;
5676 extern cvar_t v_isometric;
5677 extern void V_MakeViewIsometric(void);
5678 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5679 {
5680         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5681         int viewfbo = 0;
5682         rtexture_t *viewdepthtexture = NULL;
5683         rtexture_t *viewcolortexture = NULL;
5684         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5685
5686         // finish any 2D rendering that was queued
5687         DrawQ_Finish();
5688
5689         if (r_timereport_active)
5690                 R_TimeReport("start");
5691         r_textureframe++; // used only by R_GetCurrentTexture
5692         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5693
5694         if(R_CompileShader_CheckStaticParms())
5695                 R_GLSL_Restart_f(&cmd_client);
5696
5697         if (!r_drawentities.integer)
5698                 r_refdef.scene.numentities = 0;
5699         else if (r_sortentities.integer)
5700                 R_SortEntities();
5701
5702         R_AnimCache_ClearCache();
5703
5704         /* adjust for stereo display */
5705         if(R_Stereo_Active())
5706         {
5707                 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);
5708                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5709         }
5710
5711         if (r_refdef.view.isoverlay)
5712         {
5713                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5714                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5715                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5716                 R_TimeReport("depthclear");
5717
5718                 r_refdef.view.showdebug = false;
5719
5720                 r_fb.water.enabled = false;
5721                 r_fb.water.numwaterplanes = 0;
5722
5723                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5724
5725                 r_refdef.view.matrix = originalmatrix;
5726
5727                 CHECKGLERROR
5728                 return;
5729         }
5730
5731         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5732         {
5733                 r_refdef.view.matrix = originalmatrix;
5734                 return;
5735         }
5736
5737         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5738         if (v_isometric.integer && r_refdef.view.ismain)
5739                 V_MakeViewIsometric();
5740
5741         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5742
5743         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5744                 // in sRGB fallback, behave similar to true sRGB: convert this
5745                 // value from linear to sRGB
5746                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5747
5748         R_RenderView_UpdateViewVectors();
5749
5750         R_Shadow_UpdateWorldLightSelection();
5751
5752         // this will set up r_fb.rt_screen
5753         R_Bloom_StartFrame();
5754
5755         // apply bloom brightness offset
5756         if(r_fb.rt_bloom)
5757                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5758
5759         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5760         if (r_fb.rt_screen)
5761         {
5762                 viewfbo = r_fb.rt_screen->fbo;
5763                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5764                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5765                 viewx = 0;
5766                 viewy = 0;
5767                 viewwidth = r_fb.rt_screen->texturewidth;
5768                 viewheight = r_fb.rt_screen->textureheight;
5769         }
5770
5771         R_Water_StartFrame(viewwidth, viewheight);
5772
5773         CHECKGLERROR
5774         if (r_timereport_active)
5775                 R_TimeReport("viewsetup");
5776
5777         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5778
5779         // clear the whole fbo every frame - otherwise the driver will consider
5780         // it to be an inter-frame texture and stall in multi-gpu configurations
5781         if (r_fb.rt_screen)
5782                 GL_ScissorTest(false);
5783         R_ClearScreen(r_refdef.fogenabled);
5784         if (r_timereport_active)
5785                 R_TimeReport("viewclear");
5786
5787         r_refdef.view.clear = true;
5788
5789         r_refdef.view.showdebug = true;
5790
5791         R_View_Update();
5792         if (r_timereport_active)
5793                 R_TimeReport("visibility");
5794
5795         R_AnimCache_CacheVisibleEntities();
5796         if (r_timereport_active)
5797                 R_TimeReport("animcache");
5798
5799         R_Shadow_UpdateBounceGridTexture();
5800         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5801
5802         r_fb.water.numwaterplanes = 0;
5803         if (r_fb.water.enabled)
5804                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5805
5806         // for the actual view render we use scissoring a fair amount, so scissor
5807         // test needs to be on
5808         if (r_fb.rt_screen)
5809                 GL_ScissorTest(true);
5810         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5811         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5812         r_fb.water.numwaterplanes = 0;
5813
5814         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5815         GL_ScissorTest(false);
5816
5817         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5818         if (r_timereport_active)
5819                 R_TimeReport("blendview");
5820
5821         r_refdef.view.matrix = originalmatrix;
5822
5823         CHECKGLERROR
5824
5825         // go back to 2d rendering
5826         DrawQ_Start();
5827 }
5828
5829 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5830 {
5831         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5832         {
5833                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5834                 if (r_timereport_active)
5835                         R_TimeReport("waterworld");
5836         }
5837
5838         // don't let sound skip if going slow
5839         if (r_refdef.scene.extraupdate)
5840                 S_ExtraUpdate ();
5841
5842         R_DrawModelsAddWaterPlanes();
5843         if (r_timereport_active)
5844                 R_TimeReport("watermodels");
5845
5846         if (r_fb.water.numwaterplanes)
5847         {
5848                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5849                 if (r_timereport_active)
5850                         R_TimeReport("waterscenes");
5851         }
5852 }
5853
5854 extern cvar_t cl_locs_show;
5855 static void R_DrawLocs(void);
5856 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5857 static void R_DrawModelDecals(void);
5858 extern qbool r_shadow_usingdeferredprepass;
5859 extern int r_shadow_shadowmapatlas_modelshadows_size;
5860 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5861 {
5862         qbool shadowmapping = false;
5863
5864         if (r_timereport_active)
5865                 R_TimeReport("beginscene");
5866
5867         r_refdef.stats[r_stat_renders]++;
5868
5869         R_UpdateFog();
5870
5871         // don't let sound skip if going slow
5872         if (r_refdef.scene.extraupdate)
5873                 S_ExtraUpdate ();
5874
5875         R_MeshQueue_BeginScene();
5876
5877         R_SkyStartFrame();
5878
5879         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);
5880
5881         if (r_timereport_active)
5882                 R_TimeReport("skystartframe");
5883
5884         if (cl.csqc_vidvars.drawworld)
5885         {
5886                 // don't let sound skip if going slow
5887                 if (r_refdef.scene.extraupdate)
5888                         S_ExtraUpdate ();
5889
5890                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5891                 {
5892                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5893                         if (r_timereport_active)
5894                                 R_TimeReport("worldsky");
5895                 }
5896
5897                 if (R_DrawBrushModelsSky() && r_timereport_active)
5898                         R_TimeReport("bmodelsky");
5899
5900                 if (skyrendermasked && skyrenderlater)
5901                 {
5902                         // we have to force off the water clipping plane while rendering sky
5903                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5904                         R_Sky();
5905                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5906                         if (r_timereport_active)
5907                                 R_TimeReport("sky");
5908                 }
5909         }
5910
5911         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5912         r_shadow_viewfbo = viewfbo;
5913         r_shadow_viewdepthtexture = viewdepthtexture;
5914         r_shadow_viewcolortexture = viewcolortexture;
5915         r_shadow_viewx = viewx;
5916         r_shadow_viewy = viewy;
5917         r_shadow_viewwidth = viewwidth;
5918         r_shadow_viewheight = viewheight;
5919
5920         R_Shadow_PrepareModelShadows();
5921         R_Shadow_PrepareLights();
5922         if (r_timereport_active)
5923                 R_TimeReport("preparelights");
5924
5925         // render all the shadowmaps that will be used for this view
5926         shadowmapping = R_Shadow_ShadowMappingEnabled();
5927         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5928         {
5929                 R_Shadow_DrawShadowMaps();
5930                 if (r_timereport_active)
5931                         R_TimeReport("shadowmaps");
5932         }
5933
5934         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5935         if (r_shadow_usingdeferredprepass)
5936                 R_Shadow_DrawPrepass();
5937
5938         // now we begin the forward pass of the view render
5939         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5940         {
5941                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5942                 if (r_timereport_active)
5943                         R_TimeReport("worlddepth");
5944         }
5945         if (r_depthfirst.integer >= 2)
5946         {
5947                 R_DrawModelsDepth();
5948                 if (r_timereport_active)
5949                         R_TimeReport("modeldepth");
5950         }
5951
5952         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5953         {
5954                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5955                 if (r_timereport_active)
5956                         R_TimeReport("world");
5957         }
5958
5959         // don't let sound skip if going slow
5960         if (r_refdef.scene.extraupdate)
5961                 S_ExtraUpdate ();
5962
5963         R_DrawModels();
5964         if (r_timereport_active)
5965                 R_TimeReport("models");
5966
5967         // don't let sound skip if going slow
5968         if (r_refdef.scene.extraupdate)
5969                 S_ExtraUpdate ();
5970
5971         if (!r_shadow_usingdeferredprepass)
5972         {
5973                 R_Shadow_DrawLights();
5974                 if (r_timereport_active)
5975                         R_TimeReport("rtlights");
5976         }
5977
5978         // don't let sound skip if going slow
5979         if (r_refdef.scene.extraupdate)
5980                 S_ExtraUpdate ();
5981
5982         if (cl.csqc_vidvars.drawworld)
5983         {
5984                 R_DrawModelDecals();
5985                 if (r_timereport_active)
5986                         R_TimeReport("modeldecals");
5987
5988                 R_DrawParticles();
5989                 if (r_timereport_active)
5990                         R_TimeReport("particles");
5991
5992                 R_DrawExplosions();
5993                 if (r_timereport_active)
5994                         R_TimeReport("explosions");
5995         }
5996
5997         if (r_refdef.view.showdebug)
5998         {
5999                 if (cl_locs_show.integer)
6000                 {
6001                         R_DrawLocs();
6002                         if (r_timereport_active)
6003                                 R_TimeReport("showlocs");
6004                 }
6005
6006                 if (r_drawportals.integer)
6007                 {
6008                         R_DrawPortals();
6009                         if (r_timereport_active)
6010                                 R_TimeReport("portals");
6011                 }
6012
6013                 if (r_showbboxes_client.value > 0)
6014                 {
6015                         R_DrawEntityBBoxes(CLVM_prog);
6016                         if (r_timereport_active)
6017                                 R_TimeReport("clbboxes");
6018                 }
6019                 if (r_showbboxes.value > 0)
6020                 {
6021                         R_DrawEntityBBoxes(SVVM_prog);
6022                         if (r_timereport_active)
6023                                 R_TimeReport("svbboxes");
6024                 }
6025         }
6026
6027         if (r_transparent.integer)
6028         {
6029                 R_MeshQueue_RenderTransparent();
6030                 if (r_timereport_active)
6031                         R_TimeReport("drawtrans");
6032         }
6033
6034         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))
6035         {
6036                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6037                 if (r_timereport_active)
6038                         R_TimeReport("worlddebug");
6039                 R_DrawModelsDebug();
6040                 if (r_timereport_active)
6041                         R_TimeReport("modeldebug");
6042         }
6043
6044         if (cl.csqc_vidvars.drawworld)
6045         {
6046                 R_Shadow_DrawCoronas();
6047                 if (r_timereport_active)
6048                         R_TimeReport("coronas");
6049         }
6050
6051         // don't let sound skip if going slow
6052         if (r_refdef.scene.extraupdate)
6053                 S_ExtraUpdate ();
6054 }
6055
6056 static const unsigned short bboxelements[36] =
6057 {
6058         5, 1, 3, 5, 3, 7,
6059         6, 2, 0, 6, 0, 4,
6060         7, 3, 2, 7, 2, 6,
6061         4, 0, 1, 4, 1, 5,
6062         4, 5, 7, 4, 7, 6,
6063         1, 0, 2, 1, 2, 3,
6064 };
6065
6066 #define BBOXEDGES 13
6067 static const float bboxedges[BBOXEDGES][6] = 
6068 {
6069         // whole box
6070         { 0, 0, 0, 1, 1, 1 },
6071         // bottom edges
6072         { 0, 0, 0, 0, 1, 0 },
6073         { 0, 0, 0, 1, 0, 0 },
6074         { 0, 1, 0, 1, 1, 0 },
6075         { 1, 0, 0, 1, 1, 0 },
6076         // top edges
6077         { 0, 0, 1, 0, 1, 1 },
6078         { 0, 0, 1, 1, 0, 1 },
6079         { 0, 1, 1, 1, 1, 1 },
6080         { 1, 0, 1, 1, 1, 1 },
6081         // vertical edges
6082         { 0, 0, 0, 0, 0, 1 },
6083         { 1, 0, 0, 1, 0, 1 },
6084         { 0, 1, 0, 0, 1, 1 },
6085         { 1, 1, 0, 1, 1, 1 },
6086 };
6087
6088 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6089 {
6090         int numvertices = BBOXEDGES * 8;
6091         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6092         int numtriangles = BBOXEDGES * 12;
6093         unsigned short elements[BBOXEDGES * 36];
6094         int i, edge;
6095         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6096
6097         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6098
6099         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6100         GL_DepthMask(false);
6101         GL_DepthRange(0, 1);
6102         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6103
6104         for (edge = 0; edge < BBOXEDGES; edge++)
6105         {
6106                 for (i = 0; i < 3; i++)
6107                 {
6108                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6109                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6110                 }
6111                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6112                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6113                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6114                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6115                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6116                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6117                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6118                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6119                 for (i = 0; i < 36; i++)
6120                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6121         }
6122         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6123         if (r_refdef.fogenabled)
6124         {
6125                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6126                 {
6127                         f1 = RSurf_FogVertex(v);
6128                         f2 = 1 - f1;
6129                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6130                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6131                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6132                 }
6133         }
6134         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6135         R_Mesh_ResetTextureState();
6136         R_SetupShader_Generic_NoTexture(false, false);
6137         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6138 }
6139
6140 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6141 {
6142         // hacky overloading of the parameters
6143         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6144         int i;
6145         float color[4];
6146         prvm_edict_t *edict;
6147
6148         GL_CullFace(GL_NONE);
6149         R_SetupShader_Generic_NoTexture(false, false);
6150
6151         for (i = 0;i < numsurfaces;i++)
6152         {
6153                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6154                 switch ((int)PRVM_serveredictfloat(edict, solid))
6155                 {
6156                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6157                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6158                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6159                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6160                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6161                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6162                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6163                 }
6164                 if (prog == CLVM_prog)
6165                         color[3] *= r_showbboxes_client.value;
6166                 else
6167                         color[3] *= r_showbboxes.value;
6168                 color[3] = bound(0, color[3], 1);
6169                 GL_DepthTest(!r_showdisabledepthtest.integer);
6170                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6171         }
6172 }
6173
6174 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6175 {
6176         int i;
6177         prvm_edict_t *edict;
6178         vec3_t center;
6179
6180         if (prog == NULL)
6181                 return;
6182
6183         for (i = 0; i < prog->num_edicts; i++)
6184         {
6185                 edict = PRVM_EDICT_NUM(i);
6186                 if (edict->priv.server->free)
6187                         continue;
6188                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6189                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6190                         continue;
6191                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6192                         continue;
6193                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6194                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6195         }
6196 }
6197
6198 static const int nomodelelement3i[24] =
6199 {
6200         5, 2, 0,
6201         5, 1, 2,
6202         5, 0, 3,
6203         5, 3, 1,
6204         0, 2, 4,
6205         2, 1, 4,
6206         3, 0, 4,
6207         1, 3, 4
6208 };
6209
6210 static const unsigned short nomodelelement3s[24] =
6211 {
6212         5, 2, 0,
6213         5, 1, 2,
6214         5, 0, 3,
6215         5, 3, 1,
6216         0, 2, 4,
6217         2, 1, 4,
6218         3, 0, 4,
6219         1, 3, 4
6220 };
6221
6222 static const float nomodelvertex3f[6*3] =
6223 {
6224         -16,   0,   0,
6225          16,   0,   0,
6226           0, -16,   0,
6227           0,  16,   0,
6228           0,   0, -16,
6229           0,   0,  16
6230 };
6231
6232 static const float nomodelcolor4f[6*4] =
6233 {
6234         0.0f, 0.0f, 0.5f, 1.0f,
6235         0.0f, 0.0f, 0.5f, 1.0f,
6236         0.0f, 0.5f, 0.0f, 1.0f,
6237         0.0f, 0.5f, 0.0f, 1.0f,
6238         0.5f, 0.0f, 0.0f, 1.0f,
6239         0.5f, 0.0f, 0.0f, 1.0f
6240 };
6241
6242 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6243 {
6244         int i;
6245         float f1, f2, *c;
6246         float color4f[6*4];
6247
6248         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);
6249
6250         // this is only called once per entity so numsurfaces is always 1, and
6251         // surfacelist is always {0}, so this code does not handle batches
6252
6253         if (rsurface.ent_flags & RENDER_ADDITIVE)
6254         {
6255                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6256                 GL_DepthMask(false);
6257         }
6258         else if (ent->alpha < 1)
6259         {
6260                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6261                 GL_DepthMask(false);
6262         }
6263         else
6264         {
6265                 GL_BlendFunc(GL_ONE, GL_ZERO);
6266                 GL_DepthMask(true);
6267         }
6268         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6269         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6270         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6271         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6272         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6273         for (i = 0, c = color4f;i < 6;i++, c += 4)
6274         {
6275                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6276                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6277                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6278                 c[3] *= ent->alpha;
6279         }
6280         if (r_refdef.fogenabled)
6281         {
6282                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6283                 {
6284                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6285                         f2 = 1 - f1;
6286                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6287                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6288                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6289                 }
6290         }
6291 //      R_Mesh_ResetTextureState();
6292         R_SetupShader_Generic_NoTexture(false, false);
6293         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6294         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6295 }
6296
6297 void R_DrawNoModel(entity_render_t *ent)
6298 {
6299         vec3_t org;
6300         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6301         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6302                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6303         else
6304                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6305 }
6306
6307 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6308 {
6309         vec3_t right1, right2, diff, normal;
6310
6311         VectorSubtract (org2, org1, normal);
6312
6313         // calculate 'right' vector for start
6314         VectorSubtract (r_refdef.view.origin, org1, diff);
6315         CrossProduct (normal, diff, right1);
6316         VectorNormalize (right1);
6317
6318         // calculate 'right' vector for end
6319         VectorSubtract (r_refdef.view.origin, org2, diff);
6320         CrossProduct (normal, diff, right2);
6321         VectorNormalize (right2);
6322
6323         vert[ 0] = org1[0] + width * right1[0];
6324         vert[ 1] = org1[1] + width * right1[1];
6325         vert[ 2] = org1[2] + width * right1[2];
6326         vert[ 3] = org1[0] - width * right1[0];
6327         vert[ 4] = org1[1] - width * right1[1];
6328         vert[ 5] = org1[2] - width * right1[2];
6329         vert[ 6] = org2[0] - width * right2[0];
6330         vert[ 7] = org2[1] - width * right2[1];
6331         vert[ 8] = org2[2] - width * right2[2];
6332         vert[ 9] = org2[0] + width * right2[0];
6333         vert[10] = org2[1] + width * right2[1];
6334         vert[11] = org2[2] + width * right2[2];
6335 }
6336
6337 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)
6338 {
6339         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6340         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6341         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6342         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6343         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6344         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6345         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6346         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6347         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6348         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6349         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6350         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6351 }
6352
6353 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6354 {
6355         int i;
6356         float *vertex3f;
6357         float v[3];
6358         VectorSet(v, x, y, z);
6359         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6360                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6361                         break;
6362         if (i == mesh->numvertices)
6363         {
6364                 if (mesh->numvertices < mesh->maxvertices)
6365                 {
6366                         VectorCopy(v, vertex3f);
6367                         mesh->numvertices++;
6368                 }
6369                 return mesh->numvertices;
6370         }
6371         else
6372                 return i;
6373 }
6374
6375 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6376 {
6377         int i;
6378         int *e, element[3];
6379         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6380         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6381         e = mesh->element3i + mesh->numtriangles * 3;
6382         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6383         {
6384                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6385                 if (mesh->numtriangles < mesh->maxtriangles)
6386                 {
6387                         *e++ = element[0];
6388                         *e++ = element[1];
6389                         *e++ = element[2];
6390                         mesh->numtriangles++;
6391                 }
6392                 element[1] = element[2];
6393         }
6394 }
6395
6396 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6397 {
6398         int i;
6399         int *e, element[3];
6400         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6401         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6402         e = mesh->element3i + mesh->numtriangles * 3;
6403         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6404         {
6405                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6406                 if (mesh->numtriangles < mesh->maxtriangles)
6407                 {
6408                         *e++ = element[0];
6409                         *e++ = element[1];
6410                         *e++ = element[2];
6411                         mesh->numtriangles++;
6412                 }
6413                 element[1] = element[2];
6414         }
6415 }
6416
6417 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6418 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6419 {
6420         int planenum, planenum2;
6421         int w;
6422         int tempnumpoints;
6423         mplane_t *plane, *plane2;
6424         double maxdist;
6425         double temppoints[2][256*3];
6426         // figure out how large a bounding box we need to properly compute this brush
6427         maxdist = 0;
6428         for (w = 0;w < numplanes;w++)
6429                 maxdist = max(maxdist, fabs(planes[w].dist));
6430         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6431         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6432         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6433         {
6434                 w = 0;
6435                 tempnumpoints = 4;
6436                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6437                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6438                 {
6439                         if (planenum2 == planenum)
6440                                 continue;
6441                         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);
6442                         w = !w;
6443                 }
6444                 if (tempnumpoints < 3)
6445                         continue;
6446                 // generate elements forming a triangle fan for this polygon
6447                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6448         }
6449 }
6450
6451 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6452 {
6453         if(parms[0] == 0 && parms[1] == 0)
6454                 return false;
6455         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6456                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6457                         return false;
6458         return true;
6459 }
6460
6461 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6462 {
6463         double index, f;
6464         index = parms[2] + rsurface.shadertime * parms[3];
6465         index -= floor(index);
6466         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6467         {
6468         default:
6469         case Q3WAVEFUNC_NONE:
6470         case Q3WAVEFUNC_NOISE:
6471         case Q3WAVEFUNC_COUNT:
6472                 f = 0;
6473                 break;
6474         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6475         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6476         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6477         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6478         case Q3WAVEFUNC_TRIANGLE:
6479                 index *= 4;
6480                 f = index - floor(index);
6481                 if (index < 1)
6482                 {
6483                         // f = f;
6484                 }
6485                 else if (index < 2)
6486                         f = 1 - f;
6487                 else if (index < 3)
6488                         f = -f;
6489                 else
6490                         f = -(1 - f);
6491                 break;
6492         }
6493         f = parms[0] + parms[1] * f;
6494         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6495                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6496         return (float) f;
6497 }
6498
6499 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6500 {
6501         int w, h, idx;
6502         float shadertime;
6503         float f;
6504         float offsetd[2];
6505         float tcmat[12];
6506         matrix4x4_t matrix, temp;
6507         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6508         // it's better to have one huge fixup every 9 hours than gradual
6509         // degradation over time which looks consistently bad after many hours.
6510         //
6511         // tcmod scroll in particular suffers from this degradation which can't be
6512         // effectively worked around even with floor() tricks because we don't
6513         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6514         // a workaround involving floor() would be incorrect anyway...
6515         shadertime = rsurface.shadertime;
6516         if (shadertime >= 32768.0f)
6517                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6518         switch(tcmod->tcmod)
6519         {
6520                 case Q3TCMOD_COUNT:
6521                 case Q3TCMOD_NONE:
6522                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6523                                 matrix = r_waterscrollmatrix;
6524                         else
6525                                 matrix = identitymatrix;
6526                         break;
6527                 case Q3TCMOD_ENTITYTRANSLATE:
6528                         // this is used in Q3 to allow the gamecode to control texcoord
6529                         // scrolling on the entity, which is not supported in darkplaces yet.
6530                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6531                         break;
6532                 case Q3TCMOD_ROTATE:
6533                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6534                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6535                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6536                         break;
6537                 case Q3TCMOD_SCALE:
6538                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6539                         break;
6540                 case Q3TCMOD_SCROLL:
6541                         // this particular tcmod is a "bug for bug" compatible one with regards to
6542                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6543                         // specifically did the wrapping and so we must mimic that...
6544                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6545                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6546                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6547                         break;
6548                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6549                         w = (int) tcmod->parms[0];
6550                         h = (int) tcmod->parms[1];
6551                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6552                         f = f - floor(f);
6553                         idx = (int) floor(f * w * h);
6554                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6555                         break;
6556                 case Q3TCMOD_STRETCH:
6557                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6558                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6559                         break;
6560                 case Q3TCMOD_TRANSFORM:
6561                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6562                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6563                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6564                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6565                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6566                         break;
6567                 case Q3TCMOD_TURBULENT:
6568                         // this is handled in the RSurf_PrepareVertices function
6569                         matrix = identitymatrix;
6570                         break;
6571         }
6572         temp = *texmatrix;
6573         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6574 }
6575
6576 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6577 {
6578         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6579         char name[MAX_QPATH];
6580         skinframe_t *skinframe;
6581         unsigned char pixels[296*194];
6582         strlcpy(cache->name, skinname, sizeof(cache->name));
6583         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6584         if (developer_loading.integer)
6585                 Con_Printf("loading %s\n", name);
6586         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6587         if (!skinframe || !skinframe->base)
6588         {
6589                 unsigned char *f;
6590                 fs_offset_t filesize;
6591                 skinframe = NULL;
6592                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6593                 if (f)
6594                 {
6595                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6596                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6597                         Mem_Free(f);
6598                 }
6599         }
6600         cache->skinframe = skinframe;
6601 }
6602
6603 texture_t *R_GetCurrentTexture(texture_t *t)
6604 {
6605         int i, q;
6606         const entity_render_t *ent = rsurface.entity;
6607         model_t *model = ent->model; // when calling this, ent must not be NULL
6608         q3shaderinfo_layer_tcmod_t *tcmod;
6609         float specularscale = 0.0f;
6610
6611         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6612                 return t->currentframe;
6613         t->update_lastrenderframe = r_textureframe;
6614         t->update_lastrenderentity = (void *)ent;
6615
6616         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6617                 t->camera_entity = ent->entitynumber;
6618         else
6619                 t->camera_entity = 0;
6620
6621         // switch to an alternate material if this is a q1bsp animated material
6622         {
6623                 texture_t *texture = t;
6624                 int s = rsurface.ent_skinnum;
6625                 if ((unsigned int)s >= (unsigned int)model->numskins)
6626                         s = 0;
6627                 if (model->skinscenes)
6628                 {
6629                         if (model->skinscenes[s].framecount > 1)
6630                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6631                         else
6632                                 s = model->skinscenes[s].firstframe;
6633                 }
6634                 if (s > 0)
6635                         t = t + s * model->num_surfaces;
6636                 if (t->animated)
6637                 {
6638                         // use an alternate animation if the entity's frame is not 0,
6639                         // and only if the texture has an alternate animation
6640                         if (t->animated == 2) // q2bsp
6641                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6642                         else if (rsurface.ent_alttextures && t->anim_total[1])
6643                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6644                         else
6645                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6646                 }
6647                 texture->currentframe = t;
6648         }
6649
6650         // update currentskinframe to be a qw skin or animation frame
6651         if (rsurface.ent_qwskin >= 0)
6652         {
6653                 i = rsurface.ent_qwskin;
6654                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6655                 {
6656                         r_qwskincache_size = cl.maxclients;
6657                         if (r_qwskincache)
6658                                 Mem_Free(r_qwskincache);
6659                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6660                 }
6661                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6662                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6663                 t->currentskinframe = r_qwskincache[i].skinframe;
6664                 if (t->materialshaderpass && t->currentskinframe == NULL)
6665                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6666         }
6667         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6668                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6669         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6670                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6671
6672         t->currentmaterialflags = t->basematerialflags;
6673         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6674         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6675                 t->currentalpha *= r_wateralpha.value;
6676         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6677                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6678         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6679                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6680
6681         // decide on which type of lighting to use for this surface
6682         if (rsurface.entity->render_modellight_forced)
6683                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6684         if (rsurface.entity->render_rtlight_disabled)
6685                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6686         if (rsurface.entity->render_lightgrid)
6687                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6688         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6689         {
6690                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6691                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6692                 for (q = 0; q < 3; q++)
6693                 {
6694                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6695                         t->render_modellight_lightdir_world[q] = q == 2;
6696                         t->render_modellight_lightdir_local[q] = q == 2;
6697                         t->render_modellight_ambient[q] = 1;
6698                         t->render_modellight_diffuse[q] = 0;
6699                         t->render_modellight_specular[q] = 0;
6700                         t->render_lightmap_ambient[q] = 0;
6701                         t->render_lightmap_diffuse[q] = 0;
6702                         t->render_lightmap_specular[q] = 0;
6703                         t->render_rtlight_diffuse[q] = 0;
6704                         t->render_rtlight_specular[q] = 0;
6705                 }
6706         }
6707         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6708         {
6709                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6710                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6711                 for (q = 0; q < 3; q++)
6712                 {
6713                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6714                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[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_diffuse[q] = 0;
6718                         t->render_modellight_specular[q] = 0;
6719                         t->render_lightmap_ambient[q] = 0;
6720                         t->render_lightmap_diffuse[q] = 0;
6721                         t->render_lightmap_specular[q] = 0;
6722                         t->render_rtlight_diffuse[q] = 0;
6723                         t->render_rtlight_specular[q] = 0;
6724                 }
6725         }
6726         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6727         {
6728                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6729                 for (q = 0; q < 3; q++)
6730                 {
6731                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6732                         t->render_modellight_lightdir_world[q] = q == 2;
6733                         t->render_modellight_lightdir_local[q] = q == 2;
6734                         t->render_modellight_ambient[q] = 0;
6735                         t->render_modellight_diffuse[q] = 0;
6736                         t->render_modellight_specular[q] = 0;
6737                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6738                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6739                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6740                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6741                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6742                 }
6743         }
6744         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6745         {
6746                 // ambient + single direction light (modellight)
6747                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6748                 for (q = 0; q < 3; q++)
6749                 {
6750                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6751                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6752                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6753                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6754                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6755                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6756                         t->render_lightmap_ambient[q] = 0;
6757                         t->render_lightmap_diffuse[q] = 0;
6758                         t->render_lightmap_specular[q] = 0;
6759                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6760                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6761                 }
6762         }
6763         else
6764         {
6765                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6766                 for (q = 0; q < 3; q++)
6767                 {
6768                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6769                         t->render_modellight_lightdir_world[q] = q == 2;
6770                         t->render_modellight_lightdir_local[q] = q == 2;
6771                         t->render_modellight_ambient[q] = 0;
6772                         t->render_modellight_diffuse[q] = 0;
6773                         t->render_modellight_specular[q] = 0;
6774                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6775                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6776                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6777                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6778                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6779                 }
6780         }
6781
6782         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6783         {
6784                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6785                 // attribute, we punt it to the lightmap path and hope for the best,
6786                 // but lighting doesn't work.
6787                 //
6788                 // FIXME: this is fine for effects but CSQC polygons should be subject
6789                 // to lighting.
6790                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6791                 for (q = 0; q < 3; q++)
6792                 {
6793                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6794                         t->render_modellight_lightdir_world[q] = q == 2;
6795                         t->render_modellight_lightdir_local[q] = q == 2;
6796                         t->render_modellight_ambient[q] = 0;
6797                         t->render_modellight_diffuse[q] = 0;
6798                         t->render_modellight_specular[q] = 0;
6799                         t->render_lightmap_ambient[q] = 0;
6800                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6801                         t->render_lightmap_specular[q] = 0;
6802                         t->render_rtlight_diffuse[q] = 0;
6803                         t->render_rtlight_specular[q] = 0;
6804                 }
6805         }
6806
6807         for (q = 0; q < 3; q++)
6808         {
6809                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6810                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6811         }
6812
6813         if (rsurface.ent_flags & RENDER_ADDITIVE)
6814                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6815         else if (t->currentalpha < 1)
6816                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6817         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6818         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6819                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6820         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6821                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6822         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6823                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6824         if (t->backgroundshaderpass)
6825                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6826         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6827         {
6828                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6829                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6830         }
6831         else
6832                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6833         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6834         {
6835                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6836                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6837         }
6838         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6839                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6840
6841         // there is no tcmod
6842         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6843         {
6844                 t->currenttexmatrix = r_waterscrollmatrix;
6845                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6846         }
6847         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6848         {
6849                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6850                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6851         }
6852
6853         if (t->materialshaderpass)
6854                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6855                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6856
6857         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6858         if (t->currentskinframe->qpixels)
6859                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6860         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6861         if (!t->basetexture)
6862                 t->basetexture = r_texture_notexture;
6863         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6864         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6865         t->nmaptexture = t->currentskinframe->nmap;
6866         if (!t->nmaptexture)
6867                 t->nmaptexture = r_texture_blanknormalmap;
6868         t->glosstexture = r_texture_black;
6869         t->glowtexture = t->currentskinframe->glow;
6870         t->fogtexture = t->currentskinframe->fog;
6871         t->reflectmasktexture = t->currentskinframe->reflect;
6872         if (t->backgroundshaderpass)
6873         {
6874                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6875                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6876                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6877                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6878                 t->backgroundglosstexture = r_texture_black;
6879                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6880                 if (!t->backgroundnmaptexture)
6881                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6882                 // make sure that if glow is going to be used, both textures are not NULL
6883                 if (!t->backgroundglowtexture && t->glowtexture)
6884                         t->backgroundglowtexture = r_texture_black;
6885                 if (!t->glowtexture && t->backgroundglowtexture)
6886                         t->glowtexture = r_texture_black;
6887         }
6888         else
6889         {
6890                 t->backgroundbasetexture = r_texture_white;
6891                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6892                 t->backgroundglosstexture = r_texture_black;
6893                 t->backgroundglowtexture = NULL;
6894         }
6895         t->specularpower = r_shadow_glossexponent.value;
6896         // TODO: store reference values for these in the texture?
6897         if (r_shadow_gloss.integer > 0)
6898         {
6899                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6900                 {
6901                         if (r_shadow_glossintensity.value > 0)
6902                         {
6903                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6904                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6905                                 specularscale = r_shadow_glossintensity.value;
6906                         }
6907                 }
6908                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6909                 {
6910                         t->glosstexture = r_texture_white;
6911                         t->backgroundglosstexture = r_texture_white;
6912                         specularscale = r_shadow_gloss2intensity.value;
6913                         t->specularpower = r_shadow_gloss2exponent.value;
6914                 }
6915         }
6916         specularscale *= t->specularscalemod;
6917         t->specularpower *= t->specularpowermod;
6918
6919         // lightmaps mode looks bad with dlights using actual texturing, so turn
6920         // off the colormap and glossmap, but leave the normalmap on as it still
6921         // accurately represents the shading involved
6922         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6923         {
6924                 t->basetexture = r_texture_grey128;
6925                 t->pantstexture = r_texture_black;
6926                 t->shirttexture = r_texture_black;
6927                 if (gl_lightmaps.integer < 2)
6928                         t->nmaptexture = r_texture_blanknormalmap;
6929                 t->glosstexture = r_texture_black;
6930                 t->glowtexture = NULL;
6931                 t->fogtexture = NULL;
6932                 t->reflectmasktexture = NULL;
6933                 t->backgroundbasetexture = NULL;
6934                 if (gl_lightmaps.integer < 2)
6935                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6936                 t->backgroundglosstexture = r_texture_black;
6937                 t->backgroundglowtexture = NULL;
6938                 specularscale = 0;
6939                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6940         }
6941
6942         if (specularscale != 1.0f)
6943         {
6944                 for (q = 0; q < 3; q++)
6945                 {
6946                         t->render_modellight_specular[q] *= specularscale;
6947                         t->render_lightmap_specular[q] *= specularscale;
6948                         t->render_rtlight_specular[q] *= specularscale;
6949                 }
6950         }
6951
6952         t->currentblendfunc[0] = GL_ONE;
6953         t->currentblendfunc[1] = GL_ZERO;
6954         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6955         {
6956                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6957                 t->currentblendfunc[1] = GL_ONE;
6958         }
6959         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6960         {
6961                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6962                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6963         }
6964         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6965         {
6966                 t->currentblendfunc[0] = t->customblendfunc[0];
6967                 t->currentblendfunc[1] = t->customblendfunc[1];
6968         }
6969
6970         return t;
6971 }
6972
6973 rsurfacestate_t rsurface;
6974
6975 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6976 {
6977         model_t *model = ent->model;
6978         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6979         //      return;
6980         rsurface.entity = (entity_render_t *)ent;
6981         rsurface.skeleton = ent->skeleton;
6982         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6983         rsurface.ent_skinnum = ent->skinnum;
6984         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;
6985         rsurface.ent_flags = ent->flags;
6986         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6987                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6988         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6989         rsurface.matrix = ent->matrix;
6990         rsurface.inversematrix = ent->inversematrix;
6991         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6992         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6993         R_EntityMatrix(&rsurface.matrix);
6994         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6995         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6996         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6997         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6998         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6999         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7000         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7001         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7002         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7003         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7004         if (ent->model->brush.submodel && !prepass)
7005         {
7006                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7007                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7008         }
7009         // if the animcache code decided it should use the shader path, skip the deform step
7010         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7011         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7012         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7013         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7014         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7015         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7016         {
7017                 if (ent->animcache_vertex3f)
7018                 {
7019                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7020                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7021                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7022                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7023                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7024                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7025                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7026                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7027                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7028                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7029                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7030                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7031                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7032                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7033                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7034                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7035                 }
7036                 else if (wanttangents)
7037                 {
7038                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7039                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7040                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7041                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7042                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7043                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7044                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7045                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7046                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7047                         rsurface.modelvertex3f_vertexbuffer = NULL;
7048                         rsurface.modelvertex3f_bufferoffset = 0;
7049                         rsurface.modelvertex3f_vertexbuffer = 0;
7050                         rsurface.modelvertex3f_bufferoffset = 0;
7051                         rsurface.modelsvector3f_vertexbuffer = 0;
7052                         rsurface.modelsvector3f_bufferoffset = 0;
7053                         rsurface.modeltvector3f_vertexbuffer = 0;
7054                         rsurface.modeltvector3f_bufferoffset = 0;
7055                         rsurface.modelnormal3f_vertexbuffer = 0;
7056                         rsurface.modelnormal3f_bufferoffset = 0;
7057                 }
7058                 else if (wantnormals)
7059                 {
7060                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7061                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7062                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7063                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7064                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7065                         rsurface.modelsvector3f = NULL;
7066                         rsurface.modeltvector3f = NULL;
7067                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7068                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7069                         rsurface.modelvertex3f_vertexbuffer = NULL;
7070                         rsurface.modelvertex3f_bufferoffset = 0;
7071                         rsurface.modelvertex3f_vertexbuffer = 0;
7072                         rsurface.modelvertex3f_bufferoffset = 0;
7073                         rsurface.modelsvector3f_vertexbuffer = 0;
7074                         rsurface.modelsvector3f_bufferoffset = 0;
7075                         rsurface.modeltvector3f_vertexbuffer = 0;
7076                         rsurface.modeltvector3f_bufferoffset = 0;
7077                         rsurface.modelnormal3f_vertexbuffer = 0;
7078                         rsurface.modelnormal3f_bufferoffset = 0;
7079                 }
7080                 else
7081                 {
7082                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7083                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7084                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7085                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7086                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7087                         rsurface.modelsvector3f = NULL;
7088                         rsurface.modeltvector3f = NULL;
7089                         rsurface.modelnormal3f = NULL;
7090                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7091                         rsurface.modelvertex3f_vertexbuffer = NULL;
7092                         rsurface.modelvertex3f_bufferoffset = 0;
7093                         rsurface.modelvertex3f_vertexbuffer = 0;
7094                         rsurface.modelvertex3f_bufferoffset = 0;
7095                         rsurface.modelsvector3f_vertexbuffer = 0;
7096                         rsurface.modelsvector3f_bufferoffset = 0;
7097                         rsurface.modeltvector3f_vertexbuffer = 0;
7098                         rsurface.modeltvector3f_bufferoffset = 0;
7099                         rsurface.modelnormal3f_vertexbuffer = 0;
7100                         rsurface.modelnormal3f_bufferoffset = 0;
7101                 }
7102                 rsurface.modelgeneratedvertex = true;
7103         }
7104         else
7105         {
7106                 if (rsurface.entityskeletaltransform3x4)
7107                 {
7108                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7109                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7110                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7111                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7112                 }
7113                 else
7114                 {
7115                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7116                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7117                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7118                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7119                 }
7120                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7121                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7122                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7123                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7124                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7125                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7126                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7127                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7128                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7129                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7130                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7131                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7132                 rsurface.modelgeneratedvertex = false;
7133         }
7134         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7135         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7136         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7137         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7138         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7139         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7140         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7141         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7142         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7143         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7144         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7145         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7146         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7147         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7148         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7149         rsurface.modelelement3i = model->surfmesh.data_element3i;
7150         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7151         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7152         rsurface.modelelement3s = model->surfmesh.data_element3s;
7153         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7154         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7155         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7156         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7157         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7158         rsurface.modelsurfaces = model->data_surfaces;
7159         rsurface.batchgeneratedvertex = false;
7160         rsurface.batchfirstvertex = 0;
7161         rsurface.batchnumvertices = 0;
7162         rsurface.batchfirsttriangle = 0;
7163         rsurface.batchnumtriangles = 0;
7164         rsurface.batchvertex3f  = NULL;
7165         rsurface.batchvertex3f_vertexbuffer = NULL;
7166         rsurface.batchvertex3f_bufferoffset = 0;
7167         rsurface.batchsvector3f = NULL;
7168         rsurface.batchsvector3f_vertexbuffer = NULL;
7169         rsurface.batchsvector3f_bufferoffset = 0;
7170         rsurface.batchtvector3f = NULL;
7171         rsurface.batchtvector3f_vertexbuffer = NULL;
7172         rsurface.batchtvector3f_bufferoffset = 0;
7173         rsurface.batchnormal3f  = NULL;
7174         rsurface.batchnormal3f_vertexbuffer = NULL;
7175         rsurface.batchnormal3f_bufferoffset = 0;
7176         rsurface.batchlightmapcolor4f = NULL;
7177         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7178         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7179         rsurface.batchtexcoordtexture2f = NULL;
7180         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7181         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7182         rsurface.batchtexcoordlightmap2f = NULL;
7183         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7184         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7185         rsurface.batchskeletalindex4ub = NULL;
7186         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7187         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7188         rsurface.batchskeletalweight4ub = NULL;
7189         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7190         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7191         rsurface.batchelement3i = NULL;
7192         rsurface.batchelement3i_indexbuffer = NULL;
7193         rsurface.batchelement3i_bufferoffset = 0;
7194         rsurface.batchelement3s = NULL;
7195         rsurface.batchelement3s_indexbuffer = NULL;
7196         rsurface.batchelement3s_bufferoffset = 0;
7197         rsurface.forcecurrenttextureupdate = false;
7198 }
7199
7200 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)
7201 {
7202         rsurface.entity = r_refdef.scene.worldentity;
7203         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7204                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7205                 // A better approach could be making this copy only once per frame.
7206                 static entity_render_t custom_entity;
7207                 int q;
7208                 custom_entity = *rsurface.entity;
7209                 for (q = 0; q < 3; ++q) {
7210                         float colormod = q == 0 ? r : q == 1 ? g : b;
7211                         custom_entity.render_fullbright[q] *= colormod;
7212                         custom_entity.render_modellight_ambient[q] *= colormod;
7213                         custom_entity.render_modellight_diffuse[q] *= colormod;
7214                         custom_entity.render_lightmap_ambient[q] *= colormod;
7215                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7216                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7217                 }
7218                 custom_entity.alpha *= a;
7219                 rsurface.entity = &custom_entity;
7220         }
7221         rsurface.skeleton = NULL;
7222         rsurface.ent_skinnum = 0;
7223         rsurface.ent_qwskin = -1;
7224         rsurface.ent_flags = entflags;
7225         rsurface.shadertime = r_refdef.scene.time - shadertime;
7226         rsurface.modelnumvertices = numvertices;
7227         rsurface.modelnumtriangles = numtriangles;
7228         rsurface.matrix = *matrix;
7229         rsurface.inversematrix = *inversematrix;
7230         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7231         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7232         R_EntityMatrix(&rsurface.matrix);
7233         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7234         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7235         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7236         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7237         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7238         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7239         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7240         rsurface.frameblend[0].lerp = 1;
7241         rsurface.ent_alttextures = false;
7242         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7243         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7244         rsurface.entityskeletaltransform3x4 = NULL;
7245         rsurface.entityskeletaltransform3x4buffer = NULL;
7246         rsurface.entityskeletaltransform3x4offset = 0;
7247         rsurface.entityskeletaltransform3x4size = 0;
7248         rsurface.entityskeletalnumtransforms = 0;
7249         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7250         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7251         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7252         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7253         if (wanttangents)
7254         {
7255                 rsurface.modelvertex3f = (float *)vertex3f;
7256                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7257                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7258                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7259         }
7260         else if (wantnormals)
7261         {
7262                 rsurface.modelvertex3f = (float *)vertex3f;
7263                 rsurface.modelsvector3f = NULL;
7264                 rsurface.modeltvector3f = NULL;
7265                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7266         }
7267         else
7268         {
7269                 rsurface.modelvertex3f = (float *)vertex3f;
7270                 rsurface.modelsvector3f = NULL;
7271                 rsurface.modeltvector3f = NULL;
7272                 rsurface.modelnormal3f = NULL;
7273         }
7274         rsurface.modelvertex3f_vertexbuffer = 0;
7275         rsurface.modelvertex3f_bufferoffset = 0;
7276         rsurface.modelsvector3f_vertexbuffer = 0;
7277         rsurface.modelsvector3f_bufferoffset = 0;
7278         rsurface.modeltvector3f_vertexbuffer = 0;
7279         rsurface.modeltvector3f_bufferoffset = 0;
7280         rsurface.modelnormal3f_vertexbuffer = 0;
7281         rsurface.modelnormal3f_bufferoffset = 0;
7282         rsurface.modelgeneratedvertex = true;
7283         rsurface.modellightmapcolor4f  = (float *)color4f;
7284         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7285         rsurface.modellightmapcolor4f_bufferoffset = 0;
7286         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7287         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7288         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7289         rsurface.modeltexcoordlightmap2f  = NULL;
7290         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7291         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7292         rsurface.modelskeletalindex4ub = NULL;
7293         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7294         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7295         rsurface.modelskeletalweight4ub = NULL;
7296         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7297         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7298         rsurface.modelelement3i = (int *)element3i;
7299         rsurface.modelelement3i_indexbuffer = NULL;
7300         rsurface.modelelement3i_bufferoffset = 0;
7301         rsurface.modelelement3s = (unsigned short *)element3s;
7302         rsurface.modelelement3s_indexbuffer = NULL;
7303         rsurface.modelelement3s_bufferoffset = 0;
7304         rsurface.modellightmapoffsets = NULL;
7305         rsurface.modelsurfaces = NULL;
7306         rsurface.batchgeneratedvertex = false;
7307         rsurface.batchfirstvertex = 0;
7308         rsurface.batchnumvertices = 0;
7309         rsurface.batchfirsttriangle = 0;
7310         rsurface.batchnumtriangles = 0;
7311         rsurface.batchvertex3f  = NULL;
7312         rsurface.batchvertex3f_vertexbuffer = NULL;
7313         rsurface.batchvertex3f_bufferoffset = 0;
7314         rsurface.batchsvector3f = NULL;
7315         rsurface.batchsvector3f_vertexbuffer = NULL;
7316         rsurface.batchsvector3f_bufferoffset = 0;
7317         rsurface.batchtvector3f = NULL;
7318         rsurface.batchtvector3f_vertexbuffer = NULL;
7319         rsurface.batchtvector3f_bufferoffset = 0;
7320         rsurface.batchnormal3f  = NULL;
7321         rsurface.batchnormal3f_vertexbuffer = NULL;
7322         rsurface.batchnormal3f_bufferoffset = 0;
7323         rsurface.batchlightmapcolor4f = NULL;
7324         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7325         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7326         rsurface.batchtexcoordtexture2f = NULL;
7327         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7328         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7329         rsurface.batchtexcoordlightmap2f = NULL;
7330         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7331         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7332         rsurface.batchskeletalindex4ub = NULL;
7333         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7334         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7335         rsurface.batchskeletalweight4ub = NULL;
7336         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7337         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7338         rsurface.batchelement3i = NULL;
7339         rsurface.batchelement3i_indexbuffer = NULL;
7340         rsurface.batchelement3i_bufferoffset = 0;
7341         rsurface.batchelement3s = NULL;
7342         rsurface.batchelement3s_indexbuffer = NULL;
7343         rsurface.batchelement3s_bufferoffset = 0;
7344         rsurface.forcecurrenttextureupdate = true;
7345
7346         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7347         {
7348                 if ((wantnormals || wanttangents) && !normal3f)
7349                 {
7350                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7351                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7352                 }
7353                 if (wanttangents && !svector3f)
7354                 {
7355                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7356                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7357                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7358                 }
7359         }
7360 }
7361
7362 float RSurf_FogPoint(const float *v)
7363 {
7364         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7365         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7366         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7367         float FogHeightFade = r_refdef.fogheightfade;
7368         float fogfrac;
7369         unsigned int fogmasktableindex;
7370         if (r_refdef.fogplaneviewabove)
7371                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7372         else
7373                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7374         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7375         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7376 }
7377
7378 float RSurf_FogVertex(const float *v)
7379 {
7380         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7381         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7382         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7383         float FogHeightFade = rsurface.fogheightfade;
7384         float fogfrac;
7385         unsigned int fogmasktableindex;
7386         if (r_refdef.fogplaneviewabove)
7387                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7388         else
7389                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7390         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7391         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7392 }
7393
7394 void RSurf_UploadBuffersForBatch(void)
7395 {
7396         // 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)
7397         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7398         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7399                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7400         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7401                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7402         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7403                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7404         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7405                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7406         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7407                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7408         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7409                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7410         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7411                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7412         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7413                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7414         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7415                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7416
7417         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7418                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7419         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7420                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7421
7422         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7423         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7424         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7425         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7426         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7427         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7428         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7429         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7430         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7431         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7432 }
7433
7434 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7435 {
7436         int i;
7437         for (i = 0;i < numelements;i++)
7438                 outelement3i[i] = inelement3i[i] + adjust;
7439 }
7440
7441 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7442 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7443 {
7444         int deformindex;
7445         int firsttriangle;
7446         int numtriangles;
7447         int firstvertex;
7448         int endvertex;
7449         int numvertices;
7450         int surfacefirsttriangle;
7451         int surfacenumtriangles;
7452         int surfacefirstvertex;
7453         int surfaceendvertex;
7454         int surfacenumvertices;
7455         int batchnumsurfaces = texturenumsurfaces;
7456         int batchnumvertices;
7457         int batchnumtriangles;
7458         int i, j;
7459         qbool gaps;
7460         qbool dynamicvertex;
7461         float amplitude;
7462         float animpos;
7463         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7464         float waveparms[4];
7465         unsigned char *ub;
7466         q3shaderinfo_deform_t *deform;
7467         const msurface_t *surface, *firstsurface;
7468         if (!texturenumsurfaces)
7469                 return;
7470         // find vertex range of this surface batch
7471         gaps = false;
7472         firstsurface = texturesurfacelist[0];
7473         firsttriangle = firstsurface->num_firsttriangle;
7474         batchnumvertices = 0;
7475         batchnumtriangles = 0;
7476         firstvertex = endvertex = firstsurface->num_firstvertex;
7477         for (i = 0;i < texturenumsurfaces;i++)
7478         {
7479                 surface = texturesurfacelist[i];
7480                 if (surface != firstsurface + i)
7481                         gaps = true;
7482                 surfacefirstvertex = surface->num_firstvertex;
7483                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7484                 surfacenumvertices = surface->num_vertices;
7485                 surfacenumtriangles = surface->num_triangles;
7486                 if (firstvertex > surfacefirstvertex)
7487                         firstvertex = surfacefirstvertex;
7488                 if (endvertex < surfaceendvertex)
7489                         endvertex = surfaceendvertex;
7490                 batchnumvertices += surfacenumvertices;
7491                 batchnumtriangles += surfacenumtriangles;
7492         }
7493
7494         r_refdef.stats[r_stat_batch_batches]++;
7495         if (gaps)
7496                 r_refdef.stats[r_stat_batch_withgaps]++;
7497         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7498         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7499         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7500
7501         // we now know the vertex range used, and if there are any gaps in it
7502         rsurface.batchfirstvertex = firstvertex;
7503         rsurface.batchnumvertices = endvertex - firstvertex;
7504         rsurface.batchfirsttriangle = firsttriangle;
7505         rsurface.batchnumtriangles = batchnumtriangles;
7506
7507         // check if any dynamic vertex processing must occur
7508         dynamicvertex = false;
7509
7510         // we must use vertexbuffers for rendering, we can upload vertex buffers
7511         // easily enough but if the basevertex is non-zero it becomes more
7512         // difficult, so force dynamicvertex path in that case - it's suboptimal
7513         // but the most optimal case is to have the geometry sources provide their
7514         // own anyway.
7515         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7516                 dynamicvertex = true;
7517
7518         // a cvar to force the dynamic vertex path to be taken, for debugging
7519         if (r_batch_debugdynamicvertexpath.integer)
7520         {
7521                 if (!dynamicvertex)
7522                 {
7523                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7524                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7525                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7526                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7527                 }
7528                 dynamicvertex = true;
7529         }
7530
7531         // if there is a chance of animated vertex colors, it's a dynamic batch
7532         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7533         {
7534                 if (!dynamicvertex)
7535                 {
7536                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7537                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7538                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7539                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7540                 }
7541                 dynamicvertex = true;
7542         }
7543
7544         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7545         {
7546                 switch (deform->deform)
7547                 {
7548                 default:
7549                 case Q3DEFORM_PROJECTIONSHADOW:
7550                 case Q3DEFORM_TEXT0:
7551                 case Q3DEFORM_TEXT1:
7552                 case Q3DEFORM_TEXT2:
7553                 case Q3DEFORM_TEXT3:
7554                 case Q3DEFORM_TEXT4:
7555                 case Q3DEFORM_TEXT5:
7556                 case Q3DEFORM_TEXT6:
7557                 case Q3DEFORM_TEXT7:
7558                 case Q3DEFORM_NONE:
7559                         break;
7560                 case Q3DEFORM_AUTOSPRITE:
7561                         if (!dynamicvertex)
7562                         {
7563                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7564                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7565                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7566                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7567                         }
7568                         dynamicvertex = true;
7569                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7570                         break;
7571                 case Q3DEFORM_AUTOSPRITE2:
7572                         if (!dynamicvertex)
7573                         {
7574                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7575                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7576                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7577                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7578                         }
7579                         dynamicvertex = true;
7580                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7581                         break;
7582                 case Q3DEFORM_NORMAL:
7583                         if (!dynamicvertex)
7584                         {
7585                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7586                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7587                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7588                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7589                         }
7590                         dynamicvertex = true;
7591                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7592                         break;
7593                 case Q3DEFORM_WAVE:
7594                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7595                                 break; // if wavefunc is a nop, ignore this transform
7596                         if (!dynamicvertex)
7597                         {
7598                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7599                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7600                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7601                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7602                         }
7603                         dynamicvertex = true;
7604                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7605                         break;
7606                 case Q3DEFORM_BULGE:
7607                         if (!dynamicvertex)
7608                         {
7609                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7610                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7611                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7612                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7613                         }
7614                         dynamicvertex = true;
7615                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7616                         break;
7617                 case Q3DEFORM_MOVE:
7618                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7619                                 break; // if wavefunc is a nop, ignore this transform
7620                         if (!dynamicvertex)
7621                         {
7622                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7623                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7624                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7625                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7626                         }
7627                         dynamicvertex = true;
7628                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7629                         break;
7630                 }
7631         }
7632         if (rsurface.texture->materialshaderpass)
7633         {
7634                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7635                 {
7636                 default:
7637                 case Q3TCGEN_TEXTURE:
7638                         break;
7639                 case Q3TCGEN_LIGHTMAP:
7640                         if (!dynamicvertex)
7641                         {
7642                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7643                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7644                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7645                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7646                         }
7647                         dynamicvertex = true;
7648                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7649                         break;
7650                 case Q3TCGEN_VECTOR:
7651                         if (!dynamicvertex)
7652                         {
7653                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7654                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7655                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7656                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7657                         }
7658                         dynamicvertex = true;
7659                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7660                         break;
7661                 case Q3TCGEN_ENVIRONMENT:
7662                         if (!dynamicvertex)
7663                         {
7664                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7665                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7666                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7667                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7668                         }
7669                         dynamicvertex = true;
7670                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7671                         break;
7672                 }
7673                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7674                 {
7675                         if (!dynamicvertex)
7676                         {
7677                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7678                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7679                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7680                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7681                         }
7682                         dynamicvertex = true;
7683                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7684                 }
7685         }
7686
7687         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7688         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7689         // we ensure this by treating the vertex batch as dynamic...
7690         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7691         {
7692                 if (!dynamicvertex)
7693                 {
7694                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7695                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7696                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7697                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7698                 }
7699                 dynamicvertex = true;
7700         }
7701
7702         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7703         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7704                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7705
7706         rsurface.batchvertex3f = rsurface.modelvertex3f;
7707         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7708         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7709         rsurface.batchsvector3f = rsurface.modelsvector3f;
7710         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7711         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7712         rsurface.batchtvector3f = rsurface.modeltvector3f;
7713         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7714         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7715         rsurface.batchnormal3f = rsurface.modelnormal3f;
7716         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7717         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7718         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7719         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7720         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7721         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7722         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7723         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7724         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7725         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7726         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7727         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7728         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7729         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7730         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7731         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7732         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7733         rsurface.batchelement3i = rsurface.modelelement3i;
7734         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7735         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7736         rsurface.batchelement3s = rsurface.modelelement3s;
7737         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7738         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7739         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7740         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7741         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7742         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7743         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7744
7745         // if any dynamic vertex processing has to occur in software, we copy the
7746         // entire surface list together before processing to rebase the vertices
7747         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7748         //
7749         // if any gaps exist and we do not have a static vertex buffer, we have to
7750         // copy the surface list together to avoid wasting upload bandwidth on the
7751         // vertices in the gaps.
7752         //
7753         // if gaps exist and we have a static vertex buffer, we can choose whether
7754         // to combine the index buffer ranges into one dynamic index buffer or
7755         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7756         //
7757         // in many cases the batch is reduced to one draw call.
7758
7759         rsurface.batchmultidraw = false;
7760         rsurface.batchmultidrawnumsurfaces = 0;
7761         rsurface.batchmultidrawsurfacelist = NULL;
7762
7763         if (!dynamicvertex)
7764         {
7765                 // static vertex data, just set pointers...
7766                 rsurface.batchgeneratedvertex = false;
7767                 // if there are gaps, we want to build a combined index buffer,
7768                 // otherwise use the original static buffer with an appropriate offset
7769                 if (gaps)
7770                 {
7771                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7772                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7773                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7774                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7775                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7776                         {
7777                                 rsurface.batchmultidraw = true;
7778                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7779                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7780                                 return;
7781                         }
7782                         // build a new triangle elements array for this batch
7783                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7784                         rsurface.batchfirsttriangle = 0;
7785                         numtriangles = 0;
7786                         for (i = 0;i < texturenumsurfaces;i++)
7787                         {
7788                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7789                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7790                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7791                                 numtriangles += surfacenumtriangles;
7792                         }
7793                         rsurface.batchelement3i_indexbuffer = NULL;
7794                         rsurface.batchelement3i_bufferoffset = 0;
7795                         rsurface.batchelement3s = NULL;
7796                         rsurface.batchelement3s_indexbuffer = NULL;
7797                         rsurface.batchelement3s_bufferoffset = 0;
7798                         if (endvertex <= 65536)
7799                         {
7800                                 // make a 16bit (unsigned short) index array if possible
7801                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7802                                 for (i = 0;i < numtriangles*3;i++)
7803                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7804                         }
7805                 }
7806                 else
7807                 {
7808                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7809                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7810                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7811                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7812                 }
7813                 return;
7814         }
7815
7816         // something needs software processing, do it for real...
7817         // we only directly handle separate array data in this case and then
7818         // generate interleaved data if needed...
7819         rsurface.batchgeneratedvertex = true;
7820         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7821         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7822         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7823         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7824
7825         // now copy the vertex data into a combined array and make an index array
7826         // (this is what Quake3 does all the time)
7827         // we also apply any skeletal animation here that would have been done in
7828         // the vertex shader, because most of the dynamic vertex animation cases
7829         // need actual vertex positions and normals
7830         //if (dynamicvertex)
7831         {
7832                 rsurface.batchvertex3f = NULL;
7833                 rsurface.batchvertex3f_vertexbuffer = NULL;
7834                 rsurface.batchvertex3f_bufferoffset = 0;
7835                 rsurface.batchsvector3f = NULL;
7836                 rsurface.batchsvector3f_vertexbuffer = NULL;
7837                 rsurface.batchsvector3f_bufferoffset = 0;
7838                 rsurface.batchtvector3f = NULL;
7839                 rsurface.batchtvector3f_vertexbuffer = NULL;
7840                 rsurface.batchtvector3f_bufferoffset = 0;
7841                 rsurface.batchnormal3f = NULL;
7842                 rsurface.batchnormal3f_vertexbuffer = NULL;
7843                 rsurface.batchnormal3f_bufferoffset = 0;
7844                 rsurface.batchlightmapcolor4f = NULL;
7845                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7846                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7847                 rsurface.batchtexcoordtexture2f = NULL;
7848                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7849                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7850                 rsurface.batchtexcoordlightmap2f = NULL;
7851                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7852                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7853                 rsurface.batchskeletalindex4ub = NULL;
7854                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7855                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7856                 rsurface.batchskeletalweight4ub = NULL;
7857                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7858                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7859                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7860                 rsurface.batchelement3i_indexbuffer = NULL;
7861                 rsurface.batchelement3i_bufferoffset = 0;
7862                 rsurface.batchelement3s = NULL;
7863                 rsurface.batchelement3s_indexbuffer = NULL;
7864                 rsurface.batchelement3s_bufferoffset = 0;
7865                 rsurface.batchskeletaltransform3x4buffer = NULL;
7866                 rsurface.batchskeletaltransform3x4offset = 0;
7867                 rsurface.batchskeletaltransform3x4size = 0;
7868                 // we'll only be setting up certain arrays as needed
7869                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7870                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7871                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7872                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7873                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7874                 {
7875                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7876                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7877                 }
7878                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7879                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7880                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7881                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7882                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7883                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7884                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7885                 {
7886                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7887                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7888                 }
7889                 numvertices = 0;
7890                 numtriangles = 0;
7891                 for (i = 0;i < texturenumsurfaces;i++)
7892                 {
7893                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7894                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7895                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7896                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7897                         // copy only the data requested
7898                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7899                         {
7900                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7901                                 {
7902                                         if (rsurface.batchvertex3f)
7903                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7904                                         else
7905                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7906                                 }
7907                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7908                                 {
7909                                         if (rsurface.modelnormal3f)
7910                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7911                                         else
7912                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7913                                 }
7914                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7915                                 {
7916                                         if (rsurface.modelsvector3f)
7917                                         {
7918                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7919                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7920                                         }
7921                                         else
7922                                         {
7923                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7924                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7925                                         }
7926                                 }
7927                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7928                                 {
7929                                         if (rsurface.modellightmapcolor4f)
7930                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7931                                         else
7932                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7933                                 }
7934                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7935                                 {
7936                                         if (rsurface.modeltexcoordtexture2f)
7937                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7938                                         else
7939                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7940                                 }
7941                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7942                                 {
7943                                         if (rsurface.modeltexcoordlightmap2f)
7944                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7945                                         else
7946                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7947                                 }
7948                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7949                                 {
7950                                         if (rsurface.modelskeletalindex4ub)
7951                                         {
7952                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7953                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7954                                         }
7955                                         else
7956                                         {
7957                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7958                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7959                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7960                                                 for (j = 0;j < surfacenumvertices;j++)
7961                                                         ub[j*4] = 255;
7962                                         }
7963                                 }
7964                         }
7965                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7966                         numvertices += surfacenumvertices;
7967                         numtriangles += surfacenumtriangles;
7968                 }
7969
7970                 // generate a 16bit index array as well if possible
7971                 // (in general, dynamic batches fit)
7972                 if (numvertices <= 65536)
7973                 {
7974                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7975                         for (i = 0;i < numtriangles*3;i++)
7976                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7977                 }
7978
7979                 // since we've copied everything, the batch now starts at 0
7980                 rsurface.batchfirstvertex = 0;
7981                 rsurface.batchnumvertices = batchnumvertices;
7982                 rsurface.batchfirsttriangle = 0;
7983                 rsurface.batchnumtriangles = batchnumtriangles;
7984         }
7985
7986         // apply skeletal animation that would have been done in the vertex shader
7987         if (rsurface.batchskeletaltransform3x4)
7988         {
7989                 const unsigned char *si;
7990                 const unsigned char *sw;
7991                 const float *t[4];
7992                 const float *b = rsurface.batchskeletaltransform3x4;
7993                 float *vp, *vs, *vt, *vn;
7994                 float w[4];
7995                 float m[3][4], n[3][4];
7996                 float tp[3], ts[3], tt[3], tn[3];
7997                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7998                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7999                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8000                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8001                 si = rsurface.batchskeletalindex4ub;
8002                 sw = rsurface.batchskeletalweight4ub;
8003                 vp = rsurface.batchvertex3f;
8004                 vs = rsurface.batchsvector3f;
8005                 vt = rsurface.batchtvector3f;
8006                 vn = rsurface.batchnormal3f;
8007                 memset(m[0], 0, sizeof(m));
8008                 memset(n[0], 0, sizeof(n));
8009                 for (i = 0;i < batchnumvertices;i++)
8010                 {
8011                         t[0] = b + si[0]*12;
8012                         if (sw[0] == 255)
8013                         {
8014                                 // common case - only one matrix
8015                                 m[0][0] = t[0][ 0];
8016                                 m[0][1] = t[0][ 1];
8017                                 m[0][2] = t[0][ 2];
8018                                 m[0][3] = t[0][ 3];
8019                                 m[1][0] = t[0][ 4];
8020                                 m[1][1] = t[0][ 5];
8021                                 m[1][2] = t[0][ 6];
8022                                 m[1][3] = t[0][ 7];
8023                                 m[2][0] = t[0][ 8];
8024                                 m[2][1] = t[0][ 9];
8025                                 m[2][2] = t[0][10];
8026                                 m[2][3] = t[0][11];
8027                         }
8028                         else if (sw[2] + sw[3])
8029                         {
8030                                 // blend 4 matrices
8031                                 t[1] = b + si[1]*12;
8032                                 t[2] = b + si[2]*12;
8033                                 t[3] = b + si[3]*12;
8034                                 w[0] = sw[0] * (1.0f / 255.0f);
8035                                 w[1] = sw[1] * (1.0f / 255.0f);
8036                                 w[2] = sw[2] * (1.0f / 255.0f);
8037                                 w[3] = sw[3] * (1.0f / 255.0f);
8038                                 // blend the matrices
8039                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8040                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8041                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8042                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8043                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8044                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8045                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8046                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8047                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8048                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8049                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8050                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8051                         }
8052                         else
8053                         {
8054                                 // blend 2 matrices
8055                                 t[1] = b + si[1]*12;
8056                                 w[0] = sw[0] * (1.0f / 255.0f);
8057                                 w[1] = sw[1] * (1.0f / 255.0f);
8058                                 // blend the matrices
8059                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8060                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8061                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8062                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8063                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8064                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8065                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8066                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8067                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8068                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8069                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8070                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8071                         }
8072                         si += 4;
8073                         sw += 4;
8074                         // modify the vertex
8075                         VectorCopy(vp, tp);
8076                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8077                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8078                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8079                         vp += 3;
8080                         if (vn)
8081                         {
8082                                 // the normal transformation matrix is a set of cross products...
8083                                 CrossProduct(m[1], m[2], n[0]);
8084                                 CrossProduct(m[2], m[0], n[1]);
8085                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8086                                 VectorCopy(vn, tn);
8087                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8088                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8089                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8090                                 VectorNormalize(vn);
8091                                 vn += 3;
8092                                 if (vs)
8093                                 {
8094                                         VectorCopy(vs, ts);
8095                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8096                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8097                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8098                                         VectorNormalize(vs);
8099                                         vs += 3;
8100                                         VectorCopy(vt, tt);
8101                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8102                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8103                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8104                                         VectorNormalize(vt);
8105                                         vt += 3;
8106                                 }
8107                         }
8108                 }
8109                 rsurface.batchskeletaltransform3x4 = NULL;
8110                 rsurface.batchskeletalnumtransforms = 0;
8111         }
8112
8113         // q1bsp surfaces rendered in vertex color mode have to have colors
8114         // calculated based on lightstyles
8115         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8116         {
8117                 // generate color arrays for the surfaces in this list
8118                 int c[4];
8119                 int scale;
8120                 int size3;
8121                 const int *offsets;
8122                 const unsigned char *lm;
8123                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8124                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8125                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8126                 numvertices = 0;
8127                 for (i = 0;i < texturenumsurfaces;i++)
8128                 {
8129                         surface = texturesurfacelist[i];
8130                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8131                         surfacenumvertices = surface->num_vertices;
8132                         if (surface->lightmapinfo->samples)
8133                         {
8134                                 for (j = 0;j < surfacenumvertices;j++)
8135                                 {
8136                                         lm = surface->lightmapinfo->samples + offsets[j];
8137                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8138                                         VectorScale(lm, scale, c);
8139                                         if (surface->lightmapinfo->styles[1] != 255)
8140                                         {
8141                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8142                                                 lm += size3;
8143                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8144                                                 VectorMA(c, scale, lm, c);
8145                                                 if (surface->lightmapinfo->styles[2] != 255)
8146                                                 {
8147                                                         lm += size3;
8148                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8149                                                         VectorMA(c, scale, lm, c);
8150                                                         if (surface->lightmapinfo->styles[3] != 255)
8151                                                         {
8152                                                                 lm += size3;
8153                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8154                                                                 VectorMA(c, scale, lm, c);
8155                                                         }
8156                                                 }
8157                                         }
8158                                         c[0] >>= 7;
8159                                         c[1] >>= 7;
8160                                         c[2] >>= 7;
8161                                         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);
8162                                         numvertices++;
8163                                 }
8164                         }
8165                         else
8166                         {
8167                                 for (j = 0;j < surfacenumvertices;j++)
8168                                 {
8169                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8170                                         numvertices++;
8171                                 }
8172                         }
8173                 }
8174         }
8175
8176         // if vertices are deformed (sprite flares and things in maps, possibly
8177         // water waves, bulges and other deformations), modify the copied vertices
8178         // in place
8179         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8180         {
8181                 float scale;
8182                 switch (deform->deform)
8183                 {
8184                 default:
8185                 case Q3DEFORM_PROJECTIONSHADOW:
8186                 case Q3DEFORM_TEXT0:
8187                 case Q3DEFORM_TEXT1:
8188                 case Q3DEFORM_TEXT2:
8189                 case Q3DEFORM_TEXT3:
8190                 case Q3DEFORM_TEXT4:
8191                 case Q3DEFORM_TEXT5:
8192                 case Q3DEFORM_TEXT6:
8193                 case Q3DEFORM_TEXT7:
8194                 case Q3DEFORM_NONE:
8195                         break;
8196                 case Q3DEFORM_AUTOSPRITE:
8197                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8198                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8199                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8200                         VectorNormalize(newforward);
8201                         VectorNormalize(newright);
8202                         VectorNormalize(newup);
8203 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8204 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8205 //                      rsurface.batchvertex3f_bufferoffset = 0;
8206 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8207 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8208 //                      rsurface.batchsvector3f_bufferoffset = 0;
8209 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8210 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8211 //                      rsurface.batchtvector3f_bufferoffset = 0;
8212 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8213 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8214 //                      rsurface.batchnormal3f_bufferoffset = 0;
8215                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8216                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8217                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8218                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8219                                 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);
8220                         // a single autosprite surface can contain multiple sprites...
8221                         for (j = 0;j < batchnumvertices - 3;j += 4)
8222                         {
8223                                 VectorClear(center);
8224                                 for (i = 0;i < 4;i++)
8225                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8226                                 VectorScale(center, 0.25f, center);
8227                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8228                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8229                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8230                                 for (i = 0;i < 4;i++)
8231                                 {
8232                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8233                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8234                                 }
8235                         }
8236                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8237                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8238                         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);
8239                         break;
8240                 case Q3DEFORM_AUTOSPRITE2:
8241                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8242                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8243                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8244                         VectorNormalize(newforward);
8245                         VectorNormalize(newright);
8246                         VectorNormalize(newup);
8247 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8248 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8249 //                      rsurface.batchvertex3f_bufferoffset = 0;
8250                         {
8251                                 const float *v1, *v2;
8252                                 vec3_t start, end;
8253                                 float f, l;
8254                                 struct
8255                                 {
8256                                         float length2;
8257                                         const float *v1;
8258                                         const float *v2;
8259                                 }
8260                                 shortest[2];
8261                                 memset(shortest, 0, sizeof(shortest));
8262                                 // a single autosprite surface can contain multiple sprites...
8263                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8264                                 {
8265                                         VectorClear(center);
8266                                         for (i = 0;i < 4;i++)
8267                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8268                                         VectorScale(center, 0.25f, center);
8269                                         // find the two shortest edges, then use them to define the
8270                                         // axis vectors for rotating around the central axis
8271                                         for (i = 0;i < 6;i++)
8272                                         {
8273                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8274                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8275                                                 l = VectorDistance2(v1, v2);
8276                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8277                                                 if (v1[2] != v2[2])
8278                                                         l += (1.0f / 1024.0f);
8279                                                 if (shortest[0].length2 > l || i == 0)
8280                                                 {
8281                                                         shortest[1] = shortest[0];
8282                                                         shortest[0].length2 = l;
8283                                                         shortest[0].v1 = v1;
8284                                                         shortest[0].v2 = v2;
8285                                                 }
8286                                                 else if (shortest[1].length2 > l || i == 1)
8287                                                 {
8288                                                         shortest[1].length2 = l;
8289                                                         shortest[1].v1 = v1;
8290                                                         shortest[1].v2 = v2;
8291                                                 }
8292                                         }
8293                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8294                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8295                                         // this calculates the right vector from the shortest edge
8296                                         // and the up vector from the edge midpoints
8297                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8298                                         VectorNormalize(right);
8299                                         VectorSubtract(end, start, up);
8300                                         VectorNormalize(up);
8301                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8302                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8303                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8304                                         VectorNegate(forward, forward);
8305                                         VectorReflect(forward, 0, up, forward);
8306                                         VectorNormalize(forward);
8307                                         CrossProduct(up, forward, newright);
8308                                         VectorNormalize(newright);
8309                                         // rotate the quad around the up axis vector, this is made
8310                                         // especially easy by the fact we know the quad is flat,
8311                                         // so we only have to subtract the center position and
8312                                         // measure distance along the right vector, and then
8313                                         // multiply that by the newright vector and add back the
8314                                         // center position
8315                                         // we also need to subtract the old position to undo the
8316                                         // displacement from the center, which we do with a
8317                                         // DotProduct, the subtraction/addition of center is also
8318                                         // optimized into DotProducts here
8319                                         l = DotProduct(right, center);
8320                                         for (i = 0;i < 4;i++)
8321                                         {
8322                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8323                                                 f = DotProduct(right, v1) - l;
8324                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8325                                         }
8326                                 }
8327                         }
8328                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8329                         {
8330 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8331 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8332 //                              rsurface.batchnormal3f_bufferoffset = 0;
8333                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8334                         }
8335                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8336                         {
8337 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8338 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8339 //                              rsurface.batchsvector3f_bufferoffset = 0;
8340 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8341 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8342 //                              rsurface.batchtvector3f_bufferoffset = 0;
8343                                 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);
8344                         }
8345                         break;
8346                 case Q3DEFORM_NORMAL:
8347                         // deform the normals to make reflections wavey
8348                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8349                         rsurface.batchnormal3f_vertexbuffer = NULL;
8350                         rsurface.batchnormal3f_bufferoffset = 0;
8351                         for (j = 0;j < batchnumvertices;j++)
8352                         {
8353                                 float vertex[3];
8354                                 float *normal = rsurface.batchnormal3f + 3*j;
8355                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8356                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8357                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8358                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8359                                 VectorNormalize(normal);
8360                         }
8361                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8362                         {
8363 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8364 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8365 //                              rsurface.batchsvector3f_bufferoffset = 0;
8366 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8367 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8368 //                              rsurface.batchtvector3f_bufferoffset = 0;
8369                                 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);
8370                         }
8371                         break;
8372                 case Q3DEFORM_WAVE:
8373                         // deform vertex array to make wavey water and flags and such
8374                         waveparms[0] = deform->waveparms[0];
8375                         waveparms[1] = deform->waveparms[1];
8376                         waveparms[2] = deform->waveparms[2];
8377                         waveparms[3] = deform->waveparms[3];
8378                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8379                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8380                         // this is how a divisor of vertex influence on deformation
8381                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8382                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8383 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8384 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8385 //                      rsurface.batchvertex3f_bufferoffset = 0;
8386 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8387 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8388 //                      rsurface.batchnormal3f_bufferoffset = 0;
8389                         for (j = 0;j < batchnumvertices;j++)
8390                         {
8391                                 // if the wavefunc depends on time, evaluate it per-vertex
8392                                 if (waveparms[3])
8393                                 {
8394                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8395                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8396                                 }
8397                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8398                         }
8399                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8400                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8401                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8402                         {
8403 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8404 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8405 //                              rsurface.batchsvector3f_bufferoffset = 0;
8406 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8407 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8408 //                              rsurface.batchtvector3f_bufferoffset = 0;
8409                                 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);
8410                         }
8411                         break;
8412                 case Q3DEFORM_BULGE:
8413                         // deform vertex array to make the surface have moving bulges
8414 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8415 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8416 //                      rsurface.batchvertex3f_bufferoffset = 0;
8417 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8418 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8419 //                      rsurface.batchnormal3f_bufferoffset = 0;
8420                         for (j = 0;j < batchnumvertices;j++)
8421                         {
8422                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8423                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8424                         }
8425                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8426                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8427                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8428                         {
8429 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8430 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8431 //                              rsurface.batchsvector3f_bufferoffset = 0;
8432 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8433 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8434 //                              rsurface.batchtvector3f_bufferoffset = 0;
8435                                 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);
8436                         }
8437                         break;
8438                 case Q3DEFORM_MOVE:
8439                         // deform vertex array
8440                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8441                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8442                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8443                         VectorScale(deform->parms, scale, waveparms);
8444 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8445 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8446 //                      rsurface.batchvertex3f_bufferoffset = 0;
8447                         for (j = 0;j < batchnumvertices;j++)
8448                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8449                         break;
8450                 }
8451         }
8452
8453         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8454         {
8455         // generate texcoords based on the chosen texcoord source
8456                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8457                 {
8458                 default:
8459                 case Q3TCGEN_TEXTURE:
8460                         break;
8461                 case Q3TCGEN_LIGHTMAP:
8462         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8463         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8464         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8465                         if (rsurface.batchtexcoordlightmap2f)
8466                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8467                         break;
8468                 case Q3TCGEN_VECTOR:
8469         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8470         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8471         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8472                         for (j = 0;j < batchnumvertices;j++)
8473                         {
8474                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8475                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8476                         }
8477                         break;
8478                 case Q3TCGEN_ENVIRONMENT:
8479                         // make environment reflections using a spheremap
8480                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8481                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8482                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8483                         for (j = 0;j < batchnumvertices;j++)
8484                         {
8485                                 // identical to Q3A's method, but executed in worldspace so
8486                                 // carried models can be shiny too
8487
8488                                 float viewer[3], d, reflected[3], worldreflected[3];
8489
8490                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8491                                 // VectorNormalize(viewer);
8492
8493                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8494
8495                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8496                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8497                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8498                                 // note: this is proportinal to viewer, so we can normalize later
8499
8500                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8501                                 VectorNormalize(worldreflected);
8502
8503                                 // note: this sphere map only uses world x and z!
8504                                 // so positive and negative y will LOOK THE SAME.
8505                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8506                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8507                         }
8508                         break;
8509                 }
8510                 // the only tcmod that needs software vertex processing is turbulent, so
8511                 // check for it here and apply the changes if needed
8512                 // and we only support that as the first one
8513                 // (handling a mixture of turbulent and other tcmods would be problematic
8514                 //  without punting it entirely to a software path)
8515                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8516                 {
8517                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8518                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8519         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8520         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8521         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8522                         for (j = 0;j < batchnumvertices;j++)
8523                         {
8524                                 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);
8525                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8526                         }
8527                 }
8528         }
8529 }
8530
8531 void RSurf_DrawBatch(void)
8532 {
8533         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8534         // through the pipeline, killing it earlier in the pipeline would have
8535         // per-surface overhead rather than per-batch overhead, so it's best to
8536         // reject it here, before it hits glDraw.
8537         if (rsurface.batchnumtriangles == 0)
8538                 return;
8539 #if 0
8540         // batch debugging code
8541         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8542         {
8543                 int i;
8544                 int j;
8545                 int c;
8546                 const int *e;
8547                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8548                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8549                 {
8550                         c = e[i];
8551                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8552                         {
8553                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8554                                 {
8555                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8556                                                 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);
8557                                         break;
8558                                 }
8559                         }
8560                 }
8561         }
8562 #endif
8563         if (rsurface.batchmultidraw)
8564         {
8565                 // issue multiple draws rather than copying index data
8566                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8567                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8568                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8569                 for (i = 0;i < numsurfaces;)
8570                 {
8571                         // combine consecutive surfaces as one draw
8572                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8573                                 if (surfacelist[j] != surfacelist[k] + 1)
8574                                         break;
8575                         firstvertex = surfacelist[i]->num_firstvertex;
8576                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8577                         firsttriangle = surfacelist[i]->num_firsttriangle;
8578                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8579                         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);
8580                         i = j;
8581                 }
8582         }
8583         else
8584         {
8585                 // there is only one consecutive run of index data (may have been combined)
8586                 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);
8587         }
8588 }
8589
8590 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8591 {
8592         // pick the closest matching water plane
8593         int planeindex, vertexindex, bestplaneindex = -1;
8594         float d, bestd;
8595         vec3_t vert;
8596         const float *v;
8597         r_waterstate_waterplane_t *p;
8598         qbool prepared = false;
8599         bestd = 0;
8600         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8601         {
8602                 if(p->camera_entity != rsurface.texture->camera_entity)
8603                         continue;
8604                 d = 0;
8605                 if(!prepared)
8606                 {
8607                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8608                         prepared = true;
8609                         if(rsurface.batchnumvertices == 0)
8610                                 break;
8611                 }
8612                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8613                 {
8614                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8615                         d += fabs(PlaneDiff(vert, &p->plane));
8616                 }
8617                 if (bestd > d || bestplaneindex < 0)
8618                 {
8619                         bestd = d;
8620                         bestplaneindex = planeindex;
8621                 }
8622         }
8623         return bestplaneindex;
8624         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8625         // this situation though, as it might be better to render single larger
8626         // batches with useless stuff (backface culled for example) than to
8627         // render multiple smaller batches
8628 }
8629
8630 void RSurf_SetupDepthAndCulling(void)
8631 {
8632         // submodels are biased to avoid z-fighting with world surfaces that they
8633         // may be exactly overlapping (avoids z-fighting artifacts on certain
8634         // doors and things in Quake maps)
8635         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8636         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8637         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8638         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8639 }
8640
8641 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8642 {
8643         int j;
8644         const float *v;
8645         float p[3], mins[3], maxs[3];
8646         int scissor[4];
8647         // transparent sky would be ridiculous
8648         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8649                 return;
8650         R_SetupShader_Generic_NoTexture(false, false);
8651         skyrenderlater = true;
8652         RSurf_SetupDepthAndCulling();
8653         GL_DepthMask(true);
8654
8655         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8656         if (r_sky_scissor.integer)
8657         {
8658                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8659                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8660                 {
8661                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8662                         if (j > 0)
8663                         {
8664                                 if (mins[0] > p[0]) mins[0] = p[0];
8665                                 if (mins[1] > p[1]) mins[1] = p[1];
8666                                 if (mins[2] > p[2]) mins[2] = p[2];
8667                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8668                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8669                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8670                         }
8671                         else
8672                         {
8673                                 VectorCopy(p, mins);
8674                                 VectorCopy(p, maxs);
8675                         }
8676                 }
8677                 if (!R_ScissorForBBox(mins, maxs, scissor))
8678                 {
8679                         if (skyscissor[2])
8680                         {
8681                                 if (skyscissor[0] > scissor[0])
8682                                 {
8683                                         skyscissor[2] += skyscissor[0] - scissor[0];
8684                                         skyscissor[0] = scissor[0];
8685                                 }
8686                                 if (skyscissor[1] > scissor[1])
8687                                 {
8688                                         skyscissor[3] += skyscissor[1] - scissor[1];
8689                                         skyscissor[1] = scissor[1];
8690                                 }
8691                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8692                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8693                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8694                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8695                         }
8696                         else
8697                                 Vector4Copy(scissor, skyscissor);
8698                 }
8699         }
8700
8701         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8702         // skymasking on them, and Quake3 never did sky masking (unlike
8703         // software Quake and software Quake2), so disable the sky masking
8704         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8705         // and skymasking also looks very bad when noclipping outside the
8706         // level, so don't use it then either.
8707         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)
8708         {
8709                 R_Mesh_ResetTextureState();
8710                 if (skyrendermasked)
8711                 {
8712                         R_SetupShader_DepthOrShadow(false, false, false);
8713                         // depth-only (masking)
8714                         GL_ColorMask(0, 0, 0, 0);
8715                         // just to make sure that braindead drivers don't draw
8716                         // anything despite that colormask...
8717                         GL_BlendFunc(GL_ZERO, GL_ONE);
8718                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8719                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8720                 }
8721                 else
8722                 {
8723                         R_SetupShader_Generic_NoTexture(false, false);
8724                         // fog sky
8725                         GL_BlendFunc(GL_ONE, GL_ZERO);
8726                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8727                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8728                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8729                 }
8730                 RSurf_DrawBatch();
8731                 if (skyrendermasked)
8732                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8733         }
8734         R_Mesh_ResetTextureState();
8735         GL_Color(1, 1, 1, 1);
8736 }
8737
8738 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8739 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8740 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8741 {
8742         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8743                 return;
8744         if (prepass)
8745         {
8746                 // render screenspace normalmap to texture
8747                 GL_DepthMask(true);
8748                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8749                 RSurf_DrawBatch();
8750                 return;
8751         }
8752
8753         // bind lightmap texture
8754
8755         // water/refraction/reflection/camera surfaces have to be handled specially
8756         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8757         {
8758                 int start, end, startplaneindex;
8759                 for (start = 0;start < texturenumsurfaces;start = end)
8760                 {
8761                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8762                         if(startplaneindex < 0)
8763                         {
8764                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8765                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8766                                 end = start + 1;
8767                                 continue;
8768                         }
8769                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8770                                 ;
8771                         // now that we have a batch using the same planeindex, render it
8772                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8773                         {
8774                                 // render water or distortion background
8775                                 GL_DepthMask(true);
8776                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8777                                 RSurf_DrawBatch();
8778                                 // blend surface on top
8779                                 GL_DepthMask(false);
8780                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8781                                 RSurf_DrawBatch();
8782                         }
8783                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8784                         {
8785                                 // render surface with reflection texture as input
8786                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8787                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8788                                 RSurf_DrawBatch();
8789                         }
8790                 }
8791                 return;
8792         }
8793
8794         // render surface batch normally
8795         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8796         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8797         RSurf_DrawBatch();
8798 }
8799
8800 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8801 {
8802         int vi;
8803         int j;
8804         int texturesurfaceindex;
8805         int k;
8806         const msurface_t *surface;
8807         float surfacecolor4f[4];
8808
8809 //      R_Mesh_ResetTextureState();
8810         R_SetupShader_Generic_NoTexture(false, false);
8811
8812         GL_BlendFunc(GL_ONE, GL_ZERO);
8813         GL_DepthMask(writedepth);
8814
8815         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8816         vi = 0;
8817         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8818         {
8819                 surface = texturesurfacelist[texturesurfaceindex];
8820                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8821                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8822                 for (j = 0;j < surface->num_vertices;j++)
8823                 {
8824                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8825                         vi++;
8826                 }
8827         }
8828         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8829         RSurf_DrawBatch();
8830 }
8831
8832 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8833 {
8834         CHECKGLERROR
8835         RSurf_SetupDepthAndCulling();
8836         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8837         {
8838                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8839                 return;
8840         }
8841         switch (vid.renderpath)
8842         {
8843         case RENDERPATH_GL32:
8844         case RENDERPATH_GLES2:
8845                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8846                 break;
8847         }
8848         CHECKGLERROR
8849 }
8850
8851 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8852 {
8853         int i, j;
8854         int texturenumsurfaces, endsurface;
8855         texture_t *texture;
8856         const msurface_t *surface;
8857         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8858
8859         RSurf_ActiveModelEntity(ent, true, true, false);
8860
8861         if (r_transparentdepthmasking.integer)
8862         {
8863                 qbool setup = false;
8864                 for (i = 0;i < numsurfaces;i = j)
8865                 {
8866                         j = i + 1;
8867                         surface = rsurface.modelsurfaces + surfacelist[i];
8868                         texture = surface->texture;
8869                         rsurface.texture = R_GetCurrentTexture(texture);
8870                         rsurface.lightmaptexture = NULL;
8871                         rsurface.deluxemaptexture = NULL;
8872                         rsurface.uselightmaptexture = false;
8873                         // scan ahead until we find a different texture
8874                         endsurface = min(i + 1024, numsurfaces);
8875                         texturenumsurfaces = 0;
8876                         texturesurfacelist[texturenumsurfaces++] = surface;
8877                         for (;j < endsurface;j++)
8878                         {
8879                                 surface = rsurface.modelsurfaces + surfacelist[j];
8880                                 if (texture != surface->texture)
8881                                         break;
8882                                 texturesurfacelist[texturenumsurfaces++] = surface;
8883                         }
8884                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8885                                 continue;
8886                         // render the range of surfaces as depth
8887                         if (!setup)
8888                         {
8889                                 setup = true;
8890                                 GL_ColorMask(0,0,0,0);
8891                                 GL_Color(1,1,1,1);
8892                                 GL_DepthTest(true);
8893                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8894                                 GL_DepthMask(true);
8895 //                              R_Mesh_ResetTextureState();
8896                         }
8897                         RSurf_SetupDepthAndCulling();
8898                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8899                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8900                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8901                         RSurf_DrawBatch();
8902                 }
8903                 if (setup)
8904                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8905         }
8906
8907         for (i = 0;i < numsurfaces;i = j)
8908         {
8909                 j = i + 1;
8910                 surface = rsurface.modelsurfaces + surfacelist[i];
8911                 texture = surface->texture;
8912                 rsurface.texture = R_GetCurrentTexture(texture);
8913                 // scan ahead until we find a different texture
8914                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8915                 texturenumsurfaces = 0;
8916                 texturesurfacelist[texturenumsurfaces++] = surface;
8917                         rsurface.lightmaptexture = surface->lightmaptexture;
8918                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8919                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8920                         for (;j < endsurface;j++)
8921                         {
8922                                 surface = rsurface.modelsurfaces + surfacelist[j];
8923                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8924                                         break;
8925                                 texturesurfacelist[texturenumsurfaces++] = surface;
8926                         }
8927                 // render the range of surfaces
8928                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8929         }
8930         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8931 }
8932
8933 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8934 {
8935         // transparent surfaces get pushed off into the transparent queue
8936         int surfacelistindex;
8937         const msurface_t *surface;
8938         vec3_t tempcenter, center;
8939         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8940         {
8941                 surface = texturesurfacelist[surfacelistindex];
8942                 if (r_transparent_sortsurfacesbynearest.integer)
8943                 {
8944                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8945                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8946                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8947                 }
8948                 else
8949                 {
8950                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8951                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8952                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8953                 }
8954                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8955                 if (rsurface.entity->transparent_offset) // transparent offset
8956                 {
8957                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8958                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8959                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8960                 }
8961                 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);
8962         }
8963 }
8964
8965 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8966 {
8967         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8968                 return;
8969         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8970                 return;
8971         RSurf_SetupDepthAndCulling();
8972         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8973         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8974         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8975         RSurf_DrawBatch();
8976 }
8977
8978 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8979 {
8980         CHECKGLERROR
8981         if (ui)
8982                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8983         else if (depthonly)
8984                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8985         else if (prepass)
8986         {
8987                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8988                         return;
8989                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8990                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8991                 else
8992                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8993         }
8994         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8995                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8996         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8997                 return;
8998         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8999         {
9000                 // in the deferred case, transparent surfaces were queued during prepass
9001                 if (!r_shadow_usingdeferredprepass)
9002                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9003         }
9004         else
9005         {
9006                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9007                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9008         }
9009         CHECKGLERROR
9010 }
9011
9012 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9013 {
9014         int i, j;
9015         texture_t *texture;
9016         R_FrameData_SetMark();
9017         // break the surface list down into batches by texture and use of lightmapping
9018         for (i = 0;i < numsurfaces;i = j)
9019         {
9020                 j = i + 1;
9021                 // texture is the base texture pointer, rsurface.texture is the
9022                 // current frame/skin the texture is directing us to use (for example
9023                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9024                 // use skin 1 instead)
9025                 texture = surfacelist[i]->texture;
9026                 rsurface.texture = R_GetCurrentTexture(texture);
9027                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9028                 {
9029                         // if this texture is not the kind we want, skip ahead to the next one
9030                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9031                                 ;
9032                         continue;
9033                 }
9034                 if(depthonly || prepass)
9035                 {
9036                         rsurface.lightmaptexture = NULL;
9037                         rsurface.deluxemaptexture = NULL;
9038                         rsurface.uselightmaptexture = false;
9039                         // simply scan ahead until we find a different texture or lightmap state
9040                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9041                                 ;
9042                 }
9043                 else
9044                 {
9045                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9046                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9047                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9048                         // simply scan ahead until we find a different texture or lightmap state
9049                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9050                                 ;
9051                 }
9052                 // render the range of surfaces
9053                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9054         }
9055         R_FrameData_ReturnToMark();
9056 }
9057
9058 float locboxvertex3f[6*4*3] =
9059 {
9060         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9061         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9062         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9063         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9064         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9065         1,0,0, 0,0,0, 0,1,0, 1,1,0
9066 };
9067
9068 unsigned short locboxelements[6*2*3] =
9069 {
9070          0, 1, 2, 0, 2, 3,
9071          4, 5, 6, 4, 6, 7,
9072          8, 9,10, 8,10,11,
9073         12,13,14, 12,14,15,
9074         16,17,18, 16,18,19,
9075         20,21,22, 20,22,23
9076 };
9077
9078 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9079 {
9080         int i, j;
9081         cl_locnode_t *loc = (cl_locnode_t *)ent;
9082         vec3_t mins, size;
9083         float vertex3f[6*4*3];
9084         CHECKGLERROR
9085         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9086         GL_DepthMask(false);
9087         GL_DepthRange(0, 1);
9088         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9089         GL_DepthTest(true);
9090         GL_CullFace(GL_NONE);
9091         R_EntityMatrix(&identitymatrix);
9092
9093 //      R_Mesh_ResetTextureState();
9094
9095         i = surfacelist[0];
9096         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9097                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9098                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9099                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9100
9101         if (VectorCompare(loc->mins, loc->maxs))
9102         {
9103                 VectorSet(size, 2, 2, 2);
9104                 VectorMA(loc->mins, -0.5f, size, mins);
9105         }
9106         else
9107         {
9108                 VectorCopy(loc->mins, mins);
9109                 VectorSubtract(loc->maxs, loc->mins, size);
9110         }
9111
9112         for (i = 0;i < 6*4*3;)
9113                 for (j = 0;j < 3;j++, i++)
9114                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9115
9116         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9117         R_SetupShader_Generic_NoTexture(false, false);
9118         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9119 }
9120
9121 void R_DrawLocs(void)
9122 {
9123         int index;
9124         cl_locnode_t *loc, *nearestloc;
9125         vec3_t center;
9126         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9127         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9128         {
9129                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9130                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9131         }
9132 }
9133
9134 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9135 {
9136         if (decalsystem->decals)
9137                 Mem_Free(decalsystem->decals);
9138         memset(decalsystem, 0, sizeof(*decalsystem));
9139 }
9140
9141 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)
9142 {
9143         tridecal_t *decal;
9144         tridecal_t *decals;
9145         int i;
9146
9147         // expand or initialize the system
9148         if (decalsystem->maxdecals <= decalsystem->numdecals)
9149         {
9150                 decalsystem_t old = *decalsystem;
9151                 qbool useshortelements;
9152                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9153                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9154                 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)));
9155                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9156                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9157                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9158                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9159                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9160                 if (decalsystem->numdecals)
9161                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9162                 if (old.decals)
9163                         Mem_Free(old.decals);
9164                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9165                         decalsystem->element3i[i] = i;
9166                 if (useshortelements)
9167                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9168                                 decalsystem->element3s[i] = i;
9169         }
9170
9171         // grab a decal and search for another free slot for the next one
9172         decals = decalsystem->decals;
9173         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9174         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9175                 ;
9176         decalsystem->freedecal = i;
9177         if (decalsystem->numdecals <= i)
9178                 decalsystem->numdecals = i + 1;
9179
9180         // initialize the decal
9181         decal->lived = 0;
9182         decal->triangleindex = triangleindex;
9183         decal->surfaceindex = surfaceindex;
9184         decal->decalsequence = decalsequence;
9185         decal->color4f[0][0] = c0[0];
9186         decal->color4f[0][1] = c0[1];
9187         decal->color4f[0][2] = c0[2];
9188         decal->color4f[0][3] = 1;
9189         decal->color4f[1][0] = c1[0];
9190         decal->color4f[1][1] = c1[1];
9191         decal->color4f[1][2] = c1[2];
9192         decal->color4f[1][3] = 1;
9193         decal->color4f[2][0] = c2[0];
9194         decal->color4f[2][1] = c2[1];
9195         decal->color4f[2][2] = c2[2];
9196         decal->color4f[2][3] = 1;
9197         decal->vertex3f[0][0] = v0[0];
9198         decal->vertex3f[0][1] = v0[1];
9199         decal->vertex3f[0][2] = v0[2];
9200         decal->vertex3f[1][0] = v1[0];
9201         decal->vertex3f[1][1] = v1[1];
9202         decal->vertex3f[1][2] = v1[2];
9203         decal->vertex3f[2][0] = v2[0];
9204         decal->vertex3f[2][1] = v2[1];
9205         decal->vertex3f[2][2] = v2[2];
9206         decal->texcoord2f[0][0] = t0[0];
9207         decal->texcoord2f[0][1] = t0[1];
9208         decal->texcoord2f[1][0] = t1[0];
9209         decal->texcoord2f[1][1] = t1[1];
9210         decal->texcoord2f[2][0] = t2[0];
9211         decal->texcoord2f[2][1] = t2[1];
9212         TriangleNormal(v0, v1, v2, decal->plane);
9213         VectorNormalize(decal->plane);
9214         decal->plane[3] = DotProduct(v0, decal->plane);
9215 }
9216
9217 extern cvar_t cl_decals_bias;
9218 extern cvar_t cl_decals_models;
9219 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9220 // baseparms, parms, temps
9221 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)
9222 {
9223         int cornerindex;
9224         int index;
9225         float v[9][3];
9226         const float *vertex3f;
9227         const float *normal3f;
9228         int numpoints;
9229         float points[2][9][3];
9230         float temp[3];
9231         float tc[9][2];
9232         float f;
9233         float c[9][4];
9234         const int *e;
9235
9236         e = rsurface.modelelement3i + 3*triangleindex;
9237
9238         vertex3f = rsurface.modelvertex3f;
9239         normal3f = rsurface.modelnormal3f;
9240
9241         if (normal3f)
9242         {
9243                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9244                 {
9245                         index = 3*e[cornerindex];
9246                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9247                 }
9248         }
9249         else
9250         {
9251                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9252                 {
9253                         index = 3*e[cornerindex];
9254                         VectorCopy(vertex3f + index, v[cornerindex]);
9255                 }
9256         }
9257
9258         // cull backfaces
9259         //TriangleNormal(v[0], v[1], v[2], normal);
9260         //if (DotProduct(normal, localnormal) < 0.0f)
9261         //      continue;
9262         // clip by each of the box planes formed from the projection matrix
9263         // if anything survives, we emit the decal
9264         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]);
9265         if (numpoints < 3)
9266                 return;
9267         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]);
9268         if (numpoints < 3)
9269                 return;
9270         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]);
9271         if (numpoints < 3)
9272                 return;
9273         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]);
9274         if (numpoints < 3)
9275                 return;
9276         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]);
9277         if (numpoints < 3)
9278                 return;
9279         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]);
9280         if (numpoints < 3)
9281                 return;
9282         // some part of the triangle survived, so we have to accept it...
9283         if (dynamic)
9284         {
9285                 // dynamic always uses the original triangle
9286                 numpoints = 3;
9287                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9288                 {
9289                         index = 3*e[cornerindex];
9290                         VectorCopy(vertex3f + index, v[cornerindex]);
9291                 }
9292         }
9293         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9294         {
9295                 // convert vertex positions to texcoords
9296                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9297                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9298                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9299                 // calculate distance fade from the projection origin
9300                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9301                 f = bound(0.0f, f, 1.0f);
9302                 c[cornerindex][0] = r * f;
9303                 c[cornerindex][1] = g * f;
9304                 c[cornerindex][2] = b * f;
9305                 c[cornerindex][3] = 1.0f;
9306                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9307         }
9308         if (dynamic)
9309                 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);
9310         else
9311                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9312                         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);
9313 }
9314 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)
9315 {
9316         matrix4x4_t projection;
9317         decalsystem_t *decalsystem;
9318         qbool dynamic;
9319         model_t *model;
9320         const msurface_t *surface;
9321         const msurface_t *surfaces;
9322         const texture_t *texture;
9323         int numtriangles;
9324         int surfaceindex;
9325         int triangleindex;
9326         float localorigin[3];
9327         float localnormal[3];
9328         float localmins[3];
9329         float localmaxs[3];
9330         float localsize;
9331         //float normal[3];
9332         float planes[6][4];
9333         float angles[3];
9334         bih_t *bih;
9335         int bih_triangles_count;
9336         int bih_triangles[256];
9337         int bih_surfaces[256];
9338
9339         decalsystem = &ent->decalsystem;
9340         model = ent->model;
9341         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9342         {
9343                 R_DecalSystem_Reset(&ent->decalsystem);
9344                 return;
9345         }
9346
9347         if (!model->brush.data_leafs && !cl_decals_models.integer)
9348         {
9349                 if (decalsystem->model)
9350                         R_DecalSystem_Reset(decalsystem);
9351                 return;
9352         }
9353
9354         if (decalsystem->model != model)
9355                 R_DecalSystem_Reset(decalsystem);
9356         decalsystem->model = model;
9357
9358         RSurf_ActiveModelEntity(ent, true, false, false);
9359
9360         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9361         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9362         VectorNormalize(localnormal);
9363         localsize = worldsize*rsurface.inversematrixscale;
9364         localmins[0] = localorigin[0] - localsize;
9365         localmins[1] = localorigin[1] - localsize;
9366         localmins[2] = localorigin[2] - localsize;
9367         localmaxs[0] = localorigin[0] + localsize;
9368         localmaxs[1] = localorigin[1] + localsize;
9369         localmaxs[2] = localorigin[2] + localsize;
9370
9371         //VectorCopy(localnormal, planes[4]);
9372         //VectorVectors(planes[4], planes[2], planes[0]);
9373         AnglesFromVectors(angles, localnormal, NULL, false);
9374         AngleVectors(angles, planes[0], planes[2], planes[4]);
9375         VectorNegate(planes[0], planes[1]);
9376         VectorNegate(planes[2], planes[3]);
9377         VectorNegate(planes[4], planes[5]);
9378         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9379         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9380         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9381         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9382         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9383         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9384
9385 #if 1
9386 // works
9387 {
9388         matrix4x4_t forwardprojection;
9389         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9390         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9391 }
9392 #else
9393 // broken
9394 {
9395         float projectionvector[4][3];
9396         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9397         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9398         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9399         projectionvector[0][0] = planes[0][0] * ilocalsize;
9400         projectionvector[0][1] = planes[1][0] * ilocalsize;
9401         projectionvector[0][2] = planes[2][0] * ilocalsize;
9402         projectionvector[1][0] = planes[0][1] * ilocalsize;
9403         projectionvector[1][1] = planes[1][1] * ilocalsize;
9404         projectionvector[1][2] = planes[2][1] * ilocalsize;
9405         projectionvector[2][0] = planes[0][2] * ilocalsize;
9406         projectionvector[2][1] = planes[1][2] * ilocalsize;
9407         projectionvector[2][2] = planes[2][2] * ilocalsize;
9408         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9409         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9410         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9411         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9412 }
9413 #endif
9414
9415         dynamic = model->surfmesh.isanimated;
9416         surfaces = model->data_surfaces;
9417
9418         bih = NULL;
9419         bih_triangles_count = -1;
9420         if(!dynamic)
9421         {
9422                 if(model->render_bih.numleafs)
9423                         bih = &model->render_bih;
9424                 else if(model->collision_bih.numleafs)
9425                         bih = &model->collision_bih;
9426         }
9427         if(bih)
9428                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9429         if(bih_triangles_count == 0)
9430                 return;
9431         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9432                 return;
9433         if(bih_triangles_count > 0)
9434         {
9435                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9436                 {
9437                         surfaceindex = bih_surfaces[triangleindex];
9438                         surface = surfaces + surfaceindex;
9439                         texture = surface->texture;
9440                         if (!texture)
9441                                 continue;
9442                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9443                                 continue;
9444                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9445                                 continue;
9446                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9447                 }
9448         }
9449         else
9450         {
9451                 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
9452                 {
9453                         surface = surfaces + surfaceindex;
9454                         // check cull box first because it rejects more than any other check
9455                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9456                                 continue;
9457                         // skip transparent surfaces
9458                         texture = surface->texture;
9459                         if (!texture)
9460                                 continue;
9461                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9462                                 continue;
9463                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9464                                 continue;
9465                         numtriangles = surface->num_triangles;
9466                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9467                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9468                 }
9469         }
9470 }
9471
9472 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9473 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)
9474 {
9475         int renderentityindex;
9476         float worldmins[3];
9477         float worldmaxs[3];
9478         entity_render_t *ent;
9479
9480         worldmins[0] = worldorigin[0] - worldsize;
9481         worldmins[1] = worldorigin[1] - worldsize;
9482         worldmins[2] = worldorigin[2] - worldsize;
9483         worldmaxs[0] = worldorigin[0] + worldsize;
9484         worldmaxs[1] = worldorigin[1] + worldsize;
9485         worldmaxs[2] = worldorigin[2] + worldsize;
9486
9487         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9488
9489         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9490         {
9491                 ent = r_refdef.scene.entities[renderentityindex];
9492                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9493                         continue;
9494
9495                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9496         }
9497 }
9498
9499 typedef struct r_decalsystem_splatqueue_s
9500 {
9501         vec3_t worldorigin;
9502         vec3_t worldnormal;
9503         float color[4];
9504         float tcrange[4];
9505         float worldsize;
9506         unsigned int decalsequence;
9507 }
9508 r_decalsystem_splatqueue_t;
9509
9510 int r_decalsystem_numqueued = 0;
9511 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9512
9513 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)
9514 {
9515         r_decalsystem_splatqueue_t *queue;
9516
9517         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9518                 return;
9519
9520         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9521         VectorCopy(worldorigin, queue->worldorigin);
9522         VectorCopy(worldnormal, queue->worldnormal);
9523         Vector4Set(queue->color, r, g, b, a);
9524         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9525         queue->worldsize = worldsize;
9526         queue->decalsequence = cl.decalsequence++;
9527 }
9528
9529 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9530 {
9531         int i;
9532         r_decalsystem_splatqueue_t *queue;
9533
9534         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9535                 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);
9536         r_decalsystem_numqueued = 0;
9537 }
9538
9539 extern cvar_t cl_decals_max;
9540 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9541 {
9542         int i;
9543         decalsystem_t *decalsystem = &ent->decalsystem;
9544         int numdecals;
9545         unsigned int killsequence;
9546         tridecal_t *decal;
9547         float frametime;
9548         float lifetime;
9549
9550         if (!decalsystem->numdecals)
9551                 return;
9552
9553         if (r_showsurfaces.integer)
9554                 return;
9555
9556         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9557         {
9558                 R_DecalSystem_Reset(decalsystem);
9559                 return;
9560         }
9561
9562         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9563         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9564
9565         if (decalsystem->lastupdatetime)
9566                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9567         else
9568                 frametime = 0;
9569         decalsystem->lastupdatetime = r_refdef.scene.time;
9570         numdecals = decalsystem->numdecals;
9571
9572         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9573         {
9574                 if (decal->color4f[0][3])
9575                 {
9576                         decal->lived += frametime;
9577                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9578                         {
9579                                 memset(decal, 0, sizeof(*decal));
9580                                 if (decalsystem->freedecal > i)
9581                                         decalsystem->freedecal = i;
9582                         }
9583                 }
9584         }
9585         decal = decalsystem->decals;
9586         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9587                 numdecals--;
9588
9589         // collapse the array by shuffling the tail decals into the gaps
9590         for (;;)
9591         {
9592                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9593                         decalsystem->freedecal++;
9594                 if (decalsystem->freedecal == numdecals)
9595                         break;
9596                 decal[decalsystem->freedecal] = decal[--numdecals];
9597         }
9598
9599         decalsystem->numdecals = numdecals;
9600
9601         if (numdecals <= 0)
9602         {
9603                 // if there are no decals left, reset decalsystem
9604                 R_DecalSystem_Reset(decalsystem);
9605         }
9606 }
9607
9608 extern skinframe_t *decalskinframe;
9609 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9610 {
9611         int i;
9612         decalsystem_t *decalsystem = &ent->decalsystem;
9613         int numdecals;
9614         tridecal_t *decal;
9615         float faderate;
9616         float alpha;
9617         float *v3f;
9618         float *c4f;
9619         float *t2f;
9620         const int *e;
9621         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9622         int numtris = 0;
9623
9624         numdecals = decalsystem->numdecals;
9625         if (!numdecals)
9626                 return;
9627
9628         if (r_showsurfaces.integer)
9629                 return;
9630
9631         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9632         {
9633                 R_DecalSystem_Reset(decalsystem);
9634                 return;
9635         }
9636
9637         // if the model is static it doesn't matter what value we give for
9638         // wantnormals and wanttangents, so this logic uses only rules applicable
9639         // to a model, knowing that they are meaningless otherwise
9640         RSurf_ActiveModelEntity(ent, false, false, false);
9641
9642         decalsystem->lastupdatetime = r_refdef.scene.time;
9643
9644         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9645
9646         // update vertex positions for animated models
9647         v3f = decalsystem->vertex3f;
9648         c4f = decalsystem->color4f;
9649         t2f = decalsystem->texcoord2f;
9650         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9651         {
9652                 if (!decal->color4f[0][3])
9653                         continue;
9654
9655                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9656                         continue;
9657
9658                 // skip backfaces
9659                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9660                         continue;
9661
9662                 // update color values for fading decals
9663                 if (decal->lived >= cl_decals_time.value)
9664                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9665                 else
9666                         alpha = 1.0f;
9667
9668                 c4f[ 0] = decal->color4f[0][0] * alpha;
9669                 c4f[ 1] = decal->color4f[0][1] * alpha;
9670                 c4f[ 2] = decal->color4f[0][2] * alpha;
9671                 c4f[ 3] = 1;
9672                 c4f[ 4] = decal->color4f[1][0] * alpha;
9673                 c4f[ 5] = decal->color4f[1][1] * alpha;
9674                 c4f[ 6] = decal->color4f[1][2] * alpha;
9675                 c4f[ 7] = 1;
9676                 c4f[ 8] = decal->color4f[2][0] * alpha;
9677                 c4f[ 9] = decal->color4f[2][1] * alpha;
9678                 c4f[10] = decal->color4f[2][2] * alpha;
9679                 c4f[11] = 1;
9680
9681                 t2f[0] = decal->texcoord2f[0][0];
9682                 t2f[1] = decal->texcoord2f[0][1];
9683                 t2f[2] = decal->texcoord2f[1][0];
9684                 t2f[3] = decal->texcoord2f[1][1];
9685                 t2f[4] = decal->texcoord2f[2][0];
9686                 t2f[5] = decal->texcoord2f[2][1];
9687
9688                 // update vertex positions for animated models
9689                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9690                 {
9691                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9692                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9693                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9694                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9695                 }
9696                 else
9697                 {
9698                         VectorCopy(decal->vertex3f[0], v3f);
9699                         VectorCopy(decal->vertex3f[1], v3f + 3);
9700                         VectorCopy(decal->vertex3f[2], v3f + 6);
9701                 }
9702
9703                 if (r_refdef.fogenabled)
9704                 {
9705                         alpha = RSurf_FogVertex(v3f);
9706                         VectorScale(c4f, alpha, c4f);
9707                         alpha = RSurf_FogVertex(v3f + 3);
9708                         VectorScale(c4f + 4, alpha, c4f + 4);
9709                         alpha = RSurf_FogVertex(v3f + 6);
9710                         VectorScale(c4f + 8, alpha, c4f + 8);
9711                 }
9712
9713                 v3f += 9;
9714                 c4f += 12;
9715                 t2f += 6;
9716                 numtris++;
9717         }
9718
9719         if (numtris > 0)
9720         {
9721                 r_refdef.stats[r_stat_drawndecals] += numtris;
9722
9723                 // now render the decals all at once
9724                 // (this assumes they all use one particle font texture!)
9725                 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);
9726 //              R_Mesh_ResetTextureState();
9727                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9728                 GL_DepthMask(false);
9729                 GL_DepthRange(0, 1);
9730                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9731                 GL_DepthTest(true);
9732                 GL_CullFace(GL_NONE);
9733                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9734                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9735                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9736         }
9737 }
9738
9739 static void R_DrawModelDecals(void)
9740 {
9741         int i, numdecals;
9742
9743         // fade faster when there are too many decals
9744         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9745         for (i = 0;i < r_refdef.scene.numentities;i++)
9746                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9747
9748         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9749         for (i = 0;i < r_refdef.scene.numentities;i++)
9750                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9751                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9752
9753         R_DecalSystem_ApplySplatEntitiesQueue();
9754
9755         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9756         for (i = 0;i < r_refdef.scene.numentities;i++)
9757                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9758
9759         r_refdef.stats[r_stat_totaldecals] += numdecals;
9760
9761         if (r_showsurfaces.integer || !r_drawdecals.integer)
9762                 return;
9763
9764         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9765
9766         for (i = 0;i < r_refdef.scene.numentities;i++)
9767         {
9768                 if (!r_refdef.viewcache.entityvisible[i])
9769                         continue;
9770                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9771                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9772         }
9773 }
9774
9775 static void R_DrawDebugModel(void)
9776 {
9777         entity_render_t *ent = rsurface.entity;
9778         int j, flagsmask;
9779         const msurface_t *surface;
9780         model_t *model = ent->model;
9781
9782         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9783                 return;
9784
9785         if (r_showoverdraw.value > 0)
9786         {
9787                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9788                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9789                 R_SetupShader_Generic_NoTexture(false, false);
9790                 GL_DepthTest(false);
9791                 GL_DepthMask(false);
9792                 GL_DepthRange(0, 1);
9793                 GL_BlendFunc(GL_ONE, GL_ONE);
9794                 for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
9795                 {
9796                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9797                                 continue;
9798                         surface = model->data_surfaces + j;
9799                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9800                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9801                         {
9802                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9803                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9804                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9805                                         GL_Color(c, 0, 0, 1.0f);
9806                                 else if (ent == r_refdef.scene.worldentity)
9807                                         GL_Color(c, c, c, 1.0f);
9808                                 else
9809                                         GL_Color(0, c, 0, 1.0f);
9810                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9811                                 RSurf_DrawBatch();
9812                         }
9813                 }
9814                 rsurface.texture = NULL;
9815         }
9816
9817         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9818
9819 //      R_Mesh_ResetTextureState();
9820         R_SetupShader_Generic_NoTexture(false, false);
9821         GL_DepthRange(0, 1);
9822         GL_DepthTest(!r_showdisabledepthtest.integer);
9823         GL_DepthMask(false);
9824         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9825
9826         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9827         {
9828                 int triangleindex;
9829                 int bihleafindex;
9830                 qbool cullbox = false;
9831                 const q3mbrush_t *brush;
9832                 const bih_t *bih = &model->collision_bih;
9833                 const bih_leaf_t *bihleaf;
9834                 float vertex3f[3][3];
9835                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9836                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9837                 {
9838                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9839                                 continue;
9840                         switch (bihleaf->type)
9841                         {
9842                         case BIH_BRUSH:
9843                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9844                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9845                                 {
9846                                         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);
9847                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9848                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9849                                 }
9850                                 break;
9851                         case BIH_COLLISIONTRIANGLE:
9852                                 triangleindex = bihleaf->itemindex;
9853                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9854                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9855                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9856                                 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);
9857                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9858                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9859                                 break;
9860                         case BIH_RENDERTRIANGLE:
9861                                 triangleindex = bihleaf->itemindex;
9862                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9863                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9864                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9865                                 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);
9866                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9867                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9868                                 break;
9869                         }
9870                 }
9871         }
9872
9873         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9874
9875 #ifndef USE_GLES2
9876         if (r_showtris.value > 0 && qglPolygonMode)
9877         {
9878                 if (r_showdisabledepthtest.integer)
9879                 {
9880                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9881                         GL_DepthMask(false);
9882                 }
9883                 else
9884                 {
9885                         GL_BlendFunc(GL_ONE, GL_ZERO);
9886                         GL_DepthMask(true);
9887                 }
9888                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9889                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9890                 {
9891                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9892                                 continue;
9893                         surface = model->data_surfaces + j;
9894                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9895                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9896                         {
9897                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9898                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9899                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9900                                 else if (ent == r_refdef.scene.worldentity)
9901                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9902                                 else
9903                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9904                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9905                                 RSurf_DrawBatch();
9906                         }
9907                 }
9908                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9909                 rsurface.texture = NULL;
9910         }
9911
9912 # if 0
9913         // FIXME!  implement r_shownormals with just triangles
9914         if (r_shownormals.value != 0 && qglBegin)
9915         {
9916                 int l, k;
9917                 vec3_t v;
9918                 if (r_showdisabledepthtest.integer)
9919                 {
9920                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9921                         GL_DepthMask(false);
9922                 }
9923                 else
9924                 {
9925                         GL_BlendFunc(GL_ONE, GL_ZERO);
9926                         GL_DepthMask(true);
9927                 }
9928                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9929                 {
9930                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9931                                 continue;
9932                         surface = model->data_surfaces + j;
9933                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9934                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9935                         {
9936                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9937                                 qglBegin(GL_LINES);
9938                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9939                                 {
9940                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9941                                         {
9942                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9943                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9944                                                 qglVertex3f(v[0], v[1], v[2]);
9945                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9946                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9947                                                 qglVertex3f(v[0], v[1], v[2]);
9948                                         }
9949                                 }
9950                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9951                                 {
9952                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9953                                         {
9954                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9955                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9956                                                 qglVertex3f(v[0], v[1], v[2]);
9957                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9958                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9959                                                 qglVertex3f(v[0], v[1], v[2]);
9960                                         }
9961                                 }
9962                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9963                                 {
9964                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9965                                         {
9966                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9967                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9968                                                 qglVertex3f(v[0], v[1], v[2]);
9969                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9970                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9971                                                 qglVertex3f(v[0], v[1], v[2]);
9972                                         }
9973                                 }
9974                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9975                                 {
9976                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9977                                         {
9978                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9979                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9980                                                 qglVertex3f(v[0], v[1], v[2]);
9981                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9982                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9983                                                 qglVertex3f(v[0], v[1], v[2]);
9984                                         }
9985                                 }
9986                                 qglEnd();
9987                                 CHECKGLERROR
9988                         }
9989                 }
9990                 rsurface.texture = NULL;
9991         }
9992 # endif
9993 #endif
9994 }
9995
9996 int r_maxsurfacelist = 0;
9997 const msurface_t **r_surfacelist = NULL;
9998 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
9999 {
10000         int i, j, flagsmask;
10001         model_t *model = ent->model;
10002         msurface_t *surfaces;
10003         unsigned char *update;
10004         int numsurfacelist = 0;
10005         if (model == NULL)
10006                 return;
10007
10008         if (r_maxsurfacelist < model->num_surfaces)
10009         {
10010                 r_maxsurfacelist = model->num_surfaces;
10011                 if (r_surfacelist)
10012                         Mem_Free((msurface_t **)r_surfacelist);
10013                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10014         }
10015
10016         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10017                 RSurf_ActiveModelEntity(ent, false, false, false);
10018         else if (prepass)
10019                 RSurf_ActiveModelEntity(ent, true, true, true);
10020         else if (depthonly)
10021                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10022         else
10023                 RSurf_ActiveModelEntity(ent, true, true, false);
10024
10025         surfaces = model->data_surfaces;
10026         update = model->brushq1.lightmapupdateflags;
10027
10028         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10029
10030         if (debug)
10031         {
10032                 R_DrawDebugModel();
10033                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10034                 return;
10035         }
10036
10037         // check if this is an empty model
10038         if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
10039                 return;
10040
10041         rsurface.lightmaptexture = NULL;
10042         rsurface.deluxemaptexture = NULL;
10043         rsurface.uselightmaptexture = false;
10044         rsurface.texture = NULL;
10045         rsurface.rtlight = NULL;
10046         numsurfacelist = 0;
10047
10048         // add visible surfaces to draw list
10049         if (ent == r_refdef.scene.worldentity)
10050         {
10051                 // for the world entity, check surfacevisible
10052                 for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
10053                 {
10054                         j = model->modelsurfaces_sorted[i];
10055                         if (r_refdef.viewcache.world_surfacevisible[j])
10056                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10057                 }
10058
10059                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10060                 if (!numsurfacelist)
10061                 {
10062                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10063                         return;
10064                 }
10065         }
10066         else if (ui)
10067         {
10068                 // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
10069                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10070                         r_surfacelist[numsurfacelist++] = surfaces + i;
10071         }
10072         else
10073         {
10074                 // add all surfaces
10075                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10076                         r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
10077         }
10078
10079         /*
10080          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10081          * using style chains because most styles do not change on most frames, and most
10082          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10083          * break this rule and animate most surfaces.
10084          */
10085         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10086         {
10087                 model_brush_lightstyleinfo_t *style;
10088
10089                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10090                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10091                 {
10092                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10093                         {
10094                                 int* list = style->surfacelist;
10095                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10096                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10097                                 for (j = 0; j < style->numsurfaces; j++)
10098                                         update[list[j]] = true;
10099                         }
10100                 }
10101                 // Now check if update flags are set on any surfaces that are visible
10102                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10103                 {
10104                         /* 
10105                          * We can do less frequent texture uploads (approximately 10hz for animated
10106                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10107                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10108                          * use model->num_surfaces, not nummodelsurfaces.
10109                          */
10110                         for (i = 0; i < model->num_surfaces;i++)
10111                                 if (update[i])
10112                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10113                 }
10114                 else
10115                 {
10116                         for (i = 0; i < numsurfacelist; i++)
10117                                 if (update[r_surfacelist[i] - surfaces])
10118                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10119                 }
10120         }
10121
10122         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10123
10124         // add to stats if desired
10125         if (r_speeds.integer && !skysurfaces && !depthonly)
10126         {
10127                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10128                 for (j = 0;j < numsurfacelist;j++)
10129                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10130         }
10131
10132         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10133 }
10134
10135 void R_DebugLine(vec3_t start, vec3_t end)
10136 {
10137         model_t *mod = CL_Mesh_UI();
10138         msurface_t *surf;
10139         int e0, e1, e2, e3;
10140         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10141         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10142         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10143         vec4_t w[2], s[2];
10144
10145         // transform to screen coords first
10146         Vector4Set(w[0], start[0], start[1], start[2], 1);
10147         Vector4Set(w[1], end[0], end[1], end[2], 1);
10148         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10149         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10150         x1 = s[0][0] * vid_conwidth.value / vid.width;
10151         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10152         x2 = s[1][0] * vid_conwidth.value / vid.width;
10153         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10154         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10155
10156         // add the line to the UI mesh for drawing later
10157
10158         // width is measured in real pixels
10159         if (fabs(x2 - x1) > fabs(y2 - y1))
10160         {
10161                 offsetx = 0;
10162                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10163         }
10164         else
10165         {
10166                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10167                 offsety = 0;
10168         }
10169         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);
10170         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10171         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10172         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10173         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10174         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10175         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10176
10177 }
10178
10179
10180 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)
10181 {
10182         static texture_t texture;
10183
10184         // fake enough texture and surface state to render this geometry
10185
10186         texture.update_lastrenderframe = -1; // regenerate this texture
10187         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10188         texture.basealpha = 1.0f;
10189         texture.currentskinframe = skinframe;
10190         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10191         texture.offsetmapping = OFFSETMAPPING_OFF;
10192         texture.offsetscale = 1;
10193         texture.specularscalemod = 1;
10194         texture.specularpowermod = 1;
10195         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10196
10197         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10198 }
10199
10200 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)
10201 {
10202         static msurface_t surface;
10203         const msurface_t *surfacelist = &surface;
10204
10205         // fake enough texture and surface state to render this geometry
10206         surface.texture = texture;
10207         surface.num_triangles = numtriangles;
10208         surface.num_firsttriangle = firsttriangle;
10209         surface.num_vertices = numvertices;
10210         surface.num_firstvertex = firstvertex;
10211
10212         // now render it
10213         rsurface.texture = R_GetCurrentTexture(surface.texture);
10214         rsurface.lightmaptexture = NULL;
10215         rsurface.deluxemaptexture = NULL;
10216         rsurface.uselightmaptexture = false;
10217         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10218 }