]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
CSQC: disable lighting in R_EndPolygon()
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qbool r_loadnormalmap;
48 static qbool r_loadgloss;
49 qbool r_loadfog;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 3 shows an approximation to vertex or object color (for a very approximate view of the game)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CF_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
160 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode; the default setting of 0 uses a framebuffer render when required, and renders directly to the screen otherwise"};
161 cvar_t r_rendertarget_debug = {CF_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
162 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
163 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
164 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
165 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
166 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
167 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
168 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
169
170 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
171 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
172 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
173 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
174 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
175 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
176 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
177 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
178 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
179 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
180 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
181 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
182 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
183 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
184 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
185 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
189 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
190 cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"};
191
192 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
193 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
194 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
195 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
196 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
197 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
198 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
199 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
200 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
201
202 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
203 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
204 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
205 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
206 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
207
208 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
209 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
210
211 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
212 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
213 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
214 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
215 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
216 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
217
218 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
219 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
220 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
221 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
222 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
223 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
224 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
225 cvar_t r_hdr_irisadaptation_fade_up = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
226 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
227 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
228
229 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
230
231 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
232
233 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
234
235 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
236
237 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
238 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
239 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
240 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
241
242 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
243 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
244
245 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
246
247 // FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting.
248 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
249 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
250 {
251         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
252         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
253         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
254         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
255 };
256
257 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
258 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
259 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
260
261 extern cvar_t v_glslgamma_2d;
262
263 extern qbool v_flipped_state;
264
265 r_framebufferstate_t r_fb;
266
267 /// shadow volume bsp struct with automatically growing nodes buffer
268 svbsp_t r_svbsp;
269
270 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
271
272 rtexture_t *r_texture_blanknormalmap;
273 rtexture_t *r_texture_white;
274 rtexture_t *r_texture_grey128;
275 rtexture_t *r_texture_black;
276 rtexture_t *r_texture_notexture;
277 rtexture_t *r_texture_whitecube;
278 rtexture_t *r_texture_normalizationcube;
279 rtexture_t *r_texture_fogattenuation;
280 rtexture_t *r_texture_fogheighttexture;
281 rtexture_t *r_texture_gammaramps;
282 unsigned int r_texture_gammaramps_serial;
283 //rtexture_t *r_texture_fogintensity;
284 rtexture_t *r_texture_reflectcube;
285
286 // TODO: hash lookups?
287 typedef struct cubemapinfo_s
288 {
289         char basename[64];
290         rtexture_t *texture;
291 }
292 cubemapinfo_t;
293
294 int r_texture_numcubemaps;
295 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
296
297 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
298 unsigned int r_numqueries;
299 unsigned int r_maxqueries;
300
301 typedef struct r_qwskincache_s
302 {
303         char name[MAX_QPATH];
304         skinframe_t *skinframe;
305 }
306 r_qwskincache_t;
307
308 static r_qwskincache_t *r_qwskincache;
309 static int r_qwskincache_size;
310
311 /// vertex coordinates for a quad that covers the screen exactly
312 extern const float r_screenvertex3f[12];
313 const float r_screenvertex3f[12] =
314 {
315         0, 0, 0,
316         1, 0, 0,
317         1, 1, 0,
318         0, 1, 0
319 };
320
321 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
322 {
323         int i;
324         for (i = 0;i < verts;i++)
325         {
326                 out[0] = in[0] * r;
327                 out[1] = in[1] * g;
328                 out[2] = in[2] * b;
329                 out[3] = in[3];
330                 in += 4;
331                 out += 4;
332         }
333 }
334
335 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
336 {
337         int i;
338         for (i = 0;i < verts;i++)
339         {
340                 out[0] = r;
341                 out[1] = g;
342                 out[2] = b;
343                 out[3] = a;
344                 out += 4;
345         }
346 }
347
348 // FIXME: move this to client?
349 void FOG_clear(void)
350 {
351         if (gamemode == GAME_NEHAHRA)
352         {
353                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
354                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
355                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
356                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
357                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
358         }
359         r_refdef.fog_density = 0;
360         r_refdef.fog_red = 0;
361         r_refdef.fog_green = 0;
362         r_refdef.fog_blue = 0;
363         r_refdef.fog_alpha = 1;
364         r_refdef.fog_start = 0;
365         r_refdef.fog_end = 16384;
366         r_refdef.fog_height = 1<<30;
367         r_refdef.fog_fadedepth = 128;
368         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
369 }
370
371 static void R_BuildBlankTextures(void)
372 {
373         unsigned char data[4];
374         data[2] = 128; // normal X
375         data[1] = 128; // normal Y
376         data[0] = 255; // normal Z
377         data[3] = 255; // height
378         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
379         data[0] = 255;
380         data[1] = 255;
381         data[2] = 255;
382         data[3] = 255;
383         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
384         data[0] = 128;
385         data[1] = 128;
386         data[2] = 128;
387         data[3] = 255;
388         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
389         data[0] = 0;
390         data[1] = 0;
391         data[2] = 0;
392         data[3] = 255;
393         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
394 }
395
396 static void R_BuildNoTexture(void)
397 {
398         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
399 }
400
401 static void R_BuildWhiteCube(void)
402 {
403         unsigned char data[6*1*1*4];
404         memset(data, 255, sizeof(data));
405         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
406 }
407
408 static void R_BuildNormalizationCube(void)
409 {
410         int x, y, side;
411         vec3_t v;
412         vec_t s, t, intensity;
413 #define NORMSIZE 64
414         unsigned char *data;
415         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
416         for (side = 0;side < 6;side++)
417         {
418                 for (y = 0;y < NORMSIZE;y++)
419                 {
420                         for (x = 0;x < NORMSIZE;x++)
421                         {
422                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
423                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
424                                 switch(side)
425                                 {
426                                 default:
427                                 case 0:
428                                         v[0] = 1;
429                                         v[1] = -t;
430                                         v[2] = -s;
431                                         break;
432                                 case 1:
433                                         v[0] = -1;
434                                         v[1] = -t;
435                                         v[2] = s;
436                                         break;
437                                 case 2:
438                                         v[0] = s;
439                                         v[1] = 1;
440                                         v[2] = t;
441                                         break;
442                                 case 3:
443                                         v[0] = s;
444                                         v[1] = -1;
445                                         v[2] = -t;
446                                         break;
447                                 case 4:
448                                         v[0] = s;
449                                         v[1] = -t;
450                                         v[2] = 1;
451                                         break;
452                                 case 5:
453                                         v[0] = -s;
454                                         v[1] = -t;
455                                         v[2] = -1;
456                                         break;
457                                 }
458                                 intensity = 127.0f / sqrt(DotProduct(v, v));
459                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
460                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
461                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
462                                 data[((side*64+y)*64+x)*4+3] = 255;
463                         }
464                 }
465         }
466         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
467         Mem_Free(data);
468 }
469
470 static void R_BuildFogTexture(void)
471 {
472         int x, b;
473 #define FOGWIDTH 256
474         unsigned char data1[FOGWIDTH][4];
475         //unsigned char data2[FOGWIDTH][4];
476         double d, r, alpha;
477
478         r_refdef.fogmasktable_start = r_refdef.fog_start;
479         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
480         r_refdef.fogmasktable_range = r_refdef.fogrange;
481         r_refdef.fogmasktable_density = r_refdef.fog_density;
482
483         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
484         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
485         {
486                 d = (x * r - r_refdef.fogmasktable_start);
487                 if(developer_extra.integer)
488                         Con_DPrintf("%f ", d);
489                 d = max(0, d);
490                 if (r_fog_exp2.integer)
491                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
492                 else
493                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
494                 if(developer_extra.integer)
495                         Con_DPrintf(" : %f ", alpha);
496                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
497                 if(developer_extra.integer)
498                         Con_DPrintf(" = %f\n", alpha);
499                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
500         }
501
502         for (x = 0;x < FOGWIDTH;x++)
503         {
504                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
505                 data1[x][0] = b;
506                 data1[x][1] = b;
507                 data1[x][2] = b;
508                 data1[x][3] = 255;
509                 //data2[x][0] = 255 - b;
510                 //data2[x][1] = 255 - b;
511                 //data2[x][2] = 255 - b;
512                 //data2[x][3] = 255;
513         }
514         if (r_texture_fogattenuation)
515         {
516                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
517                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
518         }
519         else
520         {
521                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
522                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
523         }
524 }
525
526 static void R_BuildFogHeightTexture(void)
527 {
528         unsigned char *inpixels;
529         int size;
530         int x;
531         int y;
532         int j;
533         float c[4];
534         float f;
535         inpixels = NULL;
536         dp_strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
537         if (r_refdef.fogheighttexturename[0])
538                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
539         if (!inpixels)
540         {
541                 r_refdef.fog_height_tablesize = 0;
542                 if (r_texture_fogheighttexture)
543                         R_FreeTexture(r_texture_fogheighttexture);
544                 r_texture_fogheighttexture = NULL;
545                 if (r_refdef.fog_height_table2d)
546                         Mem_Free(r_refdef.fog_height_table2d);
547                 r_refdef.fog_height_table2d = NULL;
548                 if (r_refdef.fog_height_table1d)
549                         Mem_Free(r_refdef.fog_height_table1d);
550                 r_refdef.fog_height_table1d = NULL;
551                 return;
552         }
553         size = image_width;
554         r_refdef.fog_height_tablesize = size;
555         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
556         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
557         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
558         Mem_Free(inpixels);
559         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
560         // average fog color table accounting for every fog layer between a point
561         // and the camera.  (Note: attenuation is handled separately!)
562         for (y = 0;y < size;y++)
563         {
564                 for (x = 0;x < size;x++)
565                 {
566                         Vector4Clear(c);
567                         f = 0;
568                         if (x < y)
569                         {
570                                 for (j = x;j <= y;j++)
571                                 {
572                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
573                                         f++;
574                                 }
575                         }
576                         else
577                         {
578                                 for (j = x;j >= y;j--)
579                                 {
580                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
581                                         f++;
582                                 }
583                         }
584                         f = 1.0f / f;
585                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
586                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
587                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
588                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
589                 }
590         }
591         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
592 }
593
594 //=======================================================================================================================================================
595
596 static const char *builtinshaderstrings[] =
597 {
598 #include "shader_glsl.h"
599 0
600 };
601
602 //=======================================================================================================================================================
603
604 typedef struct shaderpermutationinfo_s
605 {
606         const char *pretext;
607         const char *name;
608 }
609 shaderpermutationinfo_t;
610
611 typedef struct shadermodeinfo_s
612 {
613         const char *sourcebasename;
614         const char *extension;
615         const char **builtinshaderstrings;
616         const char *pretext;
617         const char *name;
618         char *filename;
619         char *builtinstring;
620         int builtincrc;
621 }
622 shadermodeinfo_t;
623
624 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
625 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
626 {
627         {"#define USEDIFFUSE\n", " diffuse"},
628         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
629         {"#define USEVIEWTINT\n", " viewtint"},
630         {"#define USECOLORMAPPING\n", " colormapping"},
631         {"#define USESATURATION\n", " saturation"},
632         {"#define USEFOGINSIDE\n", " foginside"},
633         {"#define USEFOGOUTSIDE\n", " fogoutside"},
634         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
635         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
636         {"#define USEGAMMARAMPS\n", " gammaramps"},
637         {"#define USECUBEFILTER\n", " cubefilter"},
638         {"#define USEGLOW\n", " glow"},
639         {"#define USEBLOOM\n", " bloom"},
640         {"#define USESPECULAR\n", " specular"},
641         {"#define USEPOSTPROCESSING\n", " postprocessing"},
642         {"#define USEREFLECTION\n", " reflection"},
643         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
644         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
645         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
646         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
647         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
648         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
649         {"#define USEALPHAKILL\n", " alphakill"},
650         {"#define USEREFLECTCUBE\n", " reflectcube"},
651         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
652         {"#define USEBOUNCEGRID\n", " bouncegrid"},
653         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
654         {"#define USETRIPPY\n", " trippy"},
655         {"#define USEDEPTHRGB\n", " depthrgb"},
656         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
657         {"#define USESKELETAL\n", " skeletal"},
658         {"#define USEOCCLUDE\n", " occlude"}
659 };
660
661 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
662 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
663 {
664         // SHADERLANGUAGE_GLSL
665         {
666                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
667                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
668                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
669                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
683         },
684 };
685
686 struct r_glsl_permutation_s;
687 typedef struct r_glsl_permutation_s
688 {
689         /// hash lookup data
690         struct r_glsl_permutation_s *hashnext;
691         unsigned int mode;
692         uint64_t permutation;
693
694         /// indicates if we have tried compiling this permutation already
695         qbool compiled;
696         /// 0 if compilation failed
697         int program;
698         // texture units assigned to each detected uniform
699         int tex_Texture_First;
700         int tex_Texture_Second;
701         int tex_Texture_GammaRamps;
702         int tex_Texture_Normal;
703         int tex_Texture_Color;
704         int tex_Texture_Gloss;
705         int tex_Texture_Glow;
706         int tex_Texture_SecondaryNormal;
707         int tex_Texture_SecondaryColor;
708         int tex_Texture_SecondaryGloss;
709         int tex_Texture_SecondaryGlow;
710         int tex_Texture_Pants;
711         int tex_Texture_Shirt;
712         int tex_Texture_FogHeightTexture;
713         int tex_Texture_FogMask;
714         int tex_Texture_LightGrid;
715         int tex_Texture_Lightmap;
716         int tex_Texture_Deluxemap;
717         int tex_Texture_Attenuation;
718         int tex_Texture_Cube;
719         int tex_Texture_Refraction;
720         int tex_Texture_Reflection;
721         int tex_Texture_ShadowMap2D;
722         int tex_Texture_CubeProjection;
723         int tex_Texture_ScreenNormalMap;
724         int tex_Texture_ScreenDiffuse;
725         int tex_Texture_ScreenSpecular;
726         int tex_Texture_ReflectMask;
727         int tex_Texture_ReflectCube;
728         int tex_Texture_BounceGrid;
729         /// locations of detected uniforms in program object, or -1 if not found
730         int loc_Texture_First;
731         int loc_Texture_Second;
732         int loc_Texture_GammaRamps;
733         int loc_Texture_Normal;
734         int loc_Texture_Color;
735         int loc_Texture_Gloss;
736         int loc_Texture_Glow;
737         int loc_Texture_SecondaryNormal;
738         int loc_Texture_SecondaryColor;
739         int loc_Texture_SecondaryGloss;
740         int loc_Texture_SecondaryGlow;
741         int loc_Texture_Pants;
742         int loc_Texture_Shirt;
743         int loc_Texture_FogHeightTexture;
744         int loc_Texture_FogMask;
745         int loc_Texture_LightGrid;
746         int loc_Texture_Lightmap;
747         int loc_Texture_Deluxemap;
748         int loc_Texture_Attenuation;
749         int loc_Texture_Cube;
750         int loc_Texture_Refraction;
751         int loc_Texture_Reflection;
752         int loc_Texture_ShadowMap2D;
753         int loc_Texture_CubeProjection;
754         int loc_Texture_ScreenNormalMap;
755         int loc_Texture_ScreenDiffuse;
756         int loc_Texture_ScreenSpecular;
757         int loc_Texture_ReflectMask;
758         int loc_Texture_ReflectCube;
759         int loc_Texture_BounceGrid;
760         int loc_Alpha;
761         int loc_BloomBlur_Parameters;
762         int loc_ClientTime;
763         int loc_Color_Ambient;
764         int loc_Color_Diffuse;
765         int loc_Color_Specular;
766         int loc_Color_Glow;
767         int loc_Color_Pants;
768         int loc_Color_Shirt;
769         int loc_DeferredColor_Ambient;
770         int loc_DeferredColor_Diffuse;
771         int loc_DeferredColor_Specular;
772         int loc_DeferredMod_Diffuse;
773         int loc_DeferredMod_Specular;
774         int loc_DistortScaleRefractReflect;
775         int loc_EyePosition;
776         int loc_FogColor;
777         int loc_FogHeightFade;
778         int loc_FogPlane;
779         int loc_FogPlaneViewDist;
780         int loc_FogRangeRecip;
781         int loc_LightColor;
782         int loc_LightDir;
783         int loc_LightGridMatrix;
784         int loc_LightGridNormalMatrix;
785         int loc_LightPosition;
786         int loc_OffsetMapping_ScaleSteps;
787         int loc_OffsetMapping_LodDistance;
788         int loc_OffsetMapping_Bias;
789         int loc_PixelSize;
790         int loc_ReflectColor;
791         int loc_ReflectFactor;
792         int loc_ReflectOffset;
793         int loc_RefractColor;
794         int loc_Saturation;
795         int loc_ScreenCenterRefractReflect;
796         int loc_ScreenScaleRefractReflect;
797         int loc_ScreenToDepth;
798         int loc_ShadowMap_Parameters;
799         int loc_ShadowMap_TextureScale;
800         int loc_SpecularPower;
801         int loc_Skeletal_Transform12;
802         int loc_UserVec1;
803         int loc_UserVec2;
804         int loc_UserVec3;
805         int loc_UserVec4;
806         int loc_ColorFringe;
807         int loc_ViewTintColor;
808         int loc_ViewToLight;
809         int loc_ModelToLight;
810         int loc_TexMatrix;
811         int loc_BackgroundTexMatrix;
812         int loc_ModelViewProjectionMatrix;
813         int loc_ModelViewMatrix;
814         int loc_PixelToScreenTexCoord;
815         int loc_ModelToReflectCube;
816         int loc_ShadowMapMatrix;
817         int loc_BloomColorSubtract;
818         int loc_NormalmapScrollBlend;
819         int loc_BounceGridMatrix;
820         int loc_BounceGridIntensity;
821         /// uniform block bindings
822         int ubibind_Skeletal_Transform12_UniformBlock;
823         /// uniform block indices
824         int ubiloc_Skeletal_Transform12_UniformBlock;
825 }
826 r_glsl_permutation_t;
827
828 #define SHADERPERMUTATION_HASHSIZE 256
829
830
831 // non-degradable "lightweight" shader parameters to keep the permutations simpler
832 // these can NOT degrade! only use for simple stuff
833 enum
834 {
835         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
836         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
837         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
838         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
839         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
840         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
841         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
842         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
843         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
844         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
845         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
846         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
847         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
848         SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
849         SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
850 };
851 #define SHADERSTATICPARMS_COUNT 15
852
853 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
854 static int shaderstaticparms_count = 0;
855
856 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
857 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
858
859 extern qbool r_shadow_shadowmapsampler;
860 extern int r_shadow_shadowmappcf;
861 qbool R_CompileShader_CheckStaticParms(void)
862 {
863         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
864         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
865         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
866
867         // detect all
868         if (r_glsl_saturation_redcompensate.integer)
869                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
870         if (r_glsl_vertextextureblend_usebothalphas.integer)
871                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
872         if (r_shadow_glossexact.integer)
873                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
874         if (r_glsl_postprocess.integer)
875         {
876                 if (r_glsl_postprocess_uservec1_enable.integer)
877                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
878                 if (r_glsl_postprocess_uservec2_enable.integer)
879                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
880                 if (r_glsl_postprocess_uservec3_enable.integer)
881                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
882                 if (r_glsl_postprocess_uservec4_enable.integer)
883                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
884         }
885         if (r_fxaa.integer)
886                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
887         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
888                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
889
890         if (r_shadow_shadowmapsampler)
891                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
892         if (r_shadow_shadowmappcf > 1)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
894         else if (r_shadow_shadowmappcf)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
896         if (r_celshading.integer)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
898         if (r_celoutlines.integer)
899                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
900         if (r_colorfringe.value)
901                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
902
903         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
904 }
905
906 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
907         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
908                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
909         else \
910                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
911 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
912 {
913         shaderstaticparms_count = 0;
914
915         // emit all
916         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
917         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
918         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
919         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
931 }
932
933 /// information about each possible shader permutation
934 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
935 /// currently selected permutation
936 r_glsl_permutation_t *r_glsl_permutation;
937 /// storage for permutations linked in the hash table
938 memexpandablearray_t r_glsl_permutationarray;
939
940 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
941 {
942         //unsigned int hashdepth = 0;
943         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
944         r_glsl_permutation_t *p;
945         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
946         {
947                 if (p->mode == mode && p->permutation == permutation)
948                 {
949                         //if (hashdepth > 10)
950                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
951                         return p;
952                 }
953                 //hashdepth++;
954         }
955         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
956         p->mode = mode;
957         p->permutation = permutation;
958         p->hashnext = r_glsl_permutationhash[mode][hashindex];
959         r_glsl_permutationhash[mode][hashindex] = p;
960         //if (hashdepth > 10)
961         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
962         return p;
963 }
964
965 static char *R_ShaderStrCat(const char **strings)
966 {
967         char *string, *s;
968         const char **p = strings;
969         const char *t;
970         size_t len = 0;
971         for (p = strings;(t = *p);p++)
972                 len += strlen(t);
973         len++;
974         s = string = (char *)Mem_Alloc(r_main_mempool, len);
975         len = 0;
976         for (p = strings;(t = *p);p++)
977         {
978                 len = strlen(t);
979                 memcpy(s, t, len);
980                 s += len;
981         }
982         *s = 0;
983         return string;
984 }
985
986 static char *R_ShaderStrCat(const char **strings);
987 static void R_InitShaderModeInfo(void)
988 {
989         int i, language;
990         shadermodeinfo_t *modeinfo;
991         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
992         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
993         {
994                 for (i = 0; i < SHADERMODE_COUNT; i++)
995                 {
996                         char filename[MAX_QPATH];
997                         modeinfo = &shadermodeinfo[language][i];
998                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
999                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1000                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1001                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1002                 }
1003         }
1004 }
1005
1006 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1007 {
1008         char *shaderstring;
1009         // if the mode has no filename we have to return the builtin string
1010         if (builtinonly || !modeinfo->filename)
1011                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1012         // note that FS_LoadFile appends a 0 byte to make it a valid string
1013         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1014         if (shaderstring)
1015         {
1016                 if (printfromdisknotice)
1017                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1018                 return shaderstring;
1019         }
1020         // fall back to builtinstring
1021         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1022 }
1023
1024 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1025 {
1026         unsigned i;
1027         int ubibind;
1028         int sampler;
1029         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1030         char *sourcestring;
1031         char permutationname[256];
1032         int vertstrings_count = 0;
1033         int geomstrings_count = 0;
1034         int fragstrings_count = 0;
1035         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1036         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1037         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1038
1039         if (p->compiled)
1040                 return;
1041         p->compiled = true;
1042         p->program = 0;
1043
1044         permutationname[0] = 0;
1045         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1046
1047         dp_strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1048
1049         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1050         if(vid.support.glshaderversion >= 140)
1051         {
1052                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1053                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1054                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1055                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1056                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1057                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1058         }
1059         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1060         else if(vid.support.glshaderversion >= 130)
1061         {
1062                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1063                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1064                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1065                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1066                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1067                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1068         }
1069         // if we can do #version 120, we should (this adds the invariant keyword)
1070         else if(vid.support.glshaderversion >= 120)
1071         {
1072                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1073                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1074                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1075                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1076                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1077                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1078         }
1079         // GLES also adds several things from GLSL120
1080         switch(vid.renderpath)
1081         {
1082         case RENDERPATH_GLES2:
1083                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1084                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1085                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1086                 break;
1087         default:
1088                 break;
1089         }
1090
1091         // the first pretext is which type of shader to compile as
1092         // (later these will all be bound together as a program object)
1093         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1094         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1095         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1096
1097         // the second pretext is the mode (for example a light source)
1098         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1099         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1100         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1101         dp_strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1102
1103         // now add all the permutation pretexts
1104         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1105         {
1106                 if (permutation & (1ll<<i))
1107                 {
1108                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1109                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1110                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1111                         dp_strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1112                 }
1113                 else
1114                 {
1115                         // keep line numbers correct
1116                         vertstrings_list[vertstrings_count++] = "\n";
1117                         geomstrings_list[geomstrings_count++] = "\n";
1118                         fragstrings_list[fragstrings_count++] = "\n";
1119                 }
1120         }
1121
1122         // add static parms
1123         R_CompileShader_AddStaticParms(mode, permutation);
1124         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1125         vertstrings_count += shaderstaticparms_count;
1126         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1127         geomstrings_count += shaderstaticparms_count;
1128         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1129         fragstrings_count += shaderstaticparms_count;
1130
1131         // now append the shader text itself
1132         vertstrings_list[vertstrings_count++] = sourcestring;
1133         geomstrings_list[geomstrings_count++] = sourcestring;
1134         fragstrings_list[fragstrings_count++] = sourcestring;
1135
1136         // we don't currently use geometry shaders for anything, so just empty the list
1137         geomstrings_count = 0;
1138
1139         // compile the shader program
1140         if (vertstrings_count + geomstrings_count + fragstrings_count)
1141                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1142         if (p->program)
1143         {
1144                 CHECKGLERROR
1145                 qglUseProgram(p->program);CHECKGLERROR
1146                 // look up all the uniform variable names we care about, so we don't
1147                 // have to look them up every time we set them
1148
1149 #if 0
1150                 // debugging aid
1151                 {
1152                         GLint activeuniformindex = 0;
1153                         GLint numactiveuniforms = 0;
1154                         char uniformname[128];
1155                         GLsizei uniformnamelength = 0;
1156                         GLint uniformsize = 0;
1157                         GLenum uniformtype = 0;
1158                         memset(uniformname, 0, sizeof(uniformname));
1159                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1160                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1161                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1162                         {
1163                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1164                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1165                         }
1166                 }
1167 #endif
1168
1169                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1170                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1171                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1172                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1173                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1174                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1175                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1176                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1177                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1178                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1179                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1180                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1181                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1182                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1183                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1184                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1185                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1186                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1187                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1188                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1189                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1190                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1191                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1192                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1193                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1194                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1195                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1196                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1197                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1198                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1199                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1200                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1201                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1202                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1203                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1204                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1205                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1206                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1207                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1208                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1209                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1210                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1211                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1212                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1213                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1214                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1215                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1216                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1217                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1218                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1219                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1220                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1221                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1222                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1223                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1224                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1225                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1226                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1227                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1228                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1229                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1230                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1231                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1232                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1233                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1234                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1235                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1236                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1237                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1238                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1239                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1240                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1241                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1242                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1243                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1244                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1245                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1246                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1247                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1248                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1249                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1250                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1251                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1252                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1253                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1254                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1255                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1256                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1257                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1258                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1259                 // initialize the samplers to refer to the texture units we use
1260                 p->tex_Texture_First = -1;
1261                 p->tex_Texture_Second = -1;
1262                 p->tex_Texture_GammaRamps = -1;
1263                 p->tex_Texture_Normal = -1;
1264                 p->tex_Texture_Color = -1;
1265                 p->tex_Texture_Gloss = -1;
1266                 p->tex_Texture_Glow = -1;
1267                 p->tex_Texture_SecondaryNormal = -1;
1268                 p->tex_Texture_SecondaryColor = -1;
1269                 p->tex_Texture_SecondaryGloss = -1;
1270                 p->tex_Texture_SecondaryGlow = -1;
1271                 p->tex_Texture_Pants = -1;
1272                 p->tex_Texture_Shirt = -1;
1273                 p->tex_Texture_FogHeightTexture = -1;
1274                 p->tex_Texture_FogMask = -1;
1275                 p->tex_Texture_LightGrid = -1;
1276                 p->tex_Texture_Lightmap = -1;
1277                 p->tex_Texture_Deluxemap = -1;
1278                 p->tex_Texture_Attenuation = -1;
1279                 p->tex_Texture_Cube = -1;
1280                 p->tex_Texture_Refraction = -1;
1281                 p->tex_Texture_Reflection = -1;
1282                 p->tex_Texture_ShadowMap2D = -1;
1283                 p->tex_Texture_CubeProjection = -1;
1284                 p->tex_Texture_ScreenNormalMap = -1;
1285                 p->tex_Texture_ScreenDiffuse = -1;
1286                 p->tex_Texture_ScreenSpecular = -1;
1287                 p->tex_Texture_ReflectMask = -1;
1288                 p->tex_Texture_ReflectCube = -1;
1289                 p->tex_Texture_BounceGrid = -1;
1290                 // bind the texture samplers in use
1291                 sampler = 0;
1292                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1293                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1294                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1295                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1296                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1297                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1298                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1299                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1300                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1301                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1302                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1303                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1304                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1305                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1306                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1307                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1308                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1309                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1310                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1311                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1312                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1313                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1314                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1315                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1316                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1317                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1318                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1319                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1320                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1321                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1322                 // get the uniform block indices so we can bind them
1323                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1324 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1325                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1326 #endif
1327                 // clear the uniform block bindings
1328                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1329                 // bind the uniform blocks in use
1330                 ubibind = 0;
1331 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1332                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1333 #endif
1334                 // we're done compiling and setting up the shader, at least until it is used
1335                 CHECKGLERROR
1336                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1337         }
1338         else
1339                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1340
1341         // free the strings
1342         if (sourcestring)
1343                 Mem_Free(sourcestring);
1344 }
1345
1346 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1347 {
1348         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1349         if (r_glsl_permutation != perm)
1350         {
1351                 r_glsl_permutation = perm;
1352                 if (!r_glsl_permutation->program)
1353                 {
1354                         if (!r_glsl_permutation->compiled)
1355                         {
1356                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1357                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1358                         }
1359                         if (!r_glsl_permutation->program)
1360                         {
1361                                 // remove features until we find a valid permutation
1362                                 unsigned i;
1363                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1364                                 {
1365                                         // reduce i more quickly whenever it would not remove any bits
1366                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1367                                         if (!(permutation & j))
1368                                                 continue;
1369                                         permutation -= j;
1370                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1371                                         if (!r_glsl_permutation->compiled)
1372                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1373                                         if (r_glsl_permutation->program)
1374                                                 break;
1375                                 }
1376                                 if (i >= SHADERPERMUTATION_COUNT)
1377                                 {
1378                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1379                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1380                                         qglUseProgram(0);CHECKGLERROR
1381                                         return; // no bit left to clear, entire mode is broken
1382                                 }
1383                         }
1384                 }
1385                 CHECKGLERROR
1386                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1387         }
1388         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1389         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1390         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1391         CHECKGLERROR
1392 }
1393
1394 void R_GLSL_Restart_f(cmd_state_t *cmd)
1395 {
1396         unsigned int i, limit;
1397         switch(vid.renderpath)
1398         {
1399         case RENDERPATH_GL32:
1400         case RENDERPATH_GLES2:
1401                 {
1402                         r_glsl_permutation_t *p;
1403                         r_glsl_permutation = NULL;
1404                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1405                         for (i = 0;i < limit;i++)
1406                         {
1407                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1408                                 {
1409                                         GL_Backend_FreeProgram(p->program);
1410                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1411                                 }
1412                         }
1413                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1414                 }
1415                 break;
1416         }
1417 }
1418
1419 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1420 {
1421         unsigned i;
1422         int language, mode, dupe;
1423         char *text;
1424         shadermodeinfo_t *modeinfo;
1425         qfile_t *file;
1426
1427         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1428         {
1429                 modeinfo = shadermodeinfo[language];
1430                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1431                 {
1432                         // don't dump the same file multiple times (most or all shaders come from the same file)
1433                         for (dupe = mode - 1;dupe >= 0;dupe--)
1434                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1435                                         break;
1436                         if (dupe >= 0)
1437                                 continue;
1438                         text = modeinfo[mode].builtinstring;
1439                         if (!text)
1440                                 continue;
1441                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1442                         if (file)
1443                         {
1444                                 FS_Print(file, "/* The engine may define the following macros:\n");
1445                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1446                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1447                                         FS_Print(file, modeinfo[i].pretext);
1448                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1449                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1450                                 FS_Print(file, "*/\n");
1451                                 FS_Print(file, text);
1452                                 FS_Close(file);
1453                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1454                         }
1455                         else
1456                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1457                 }
1458         }
1459 }
1460
1461 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1462 {
1463         uint64_t permutation = 0;
1464         if (r_trippy.integer && !notrippy)
1465                 permutation |= SHADERPERMUTATION_TRIPPY;
1466         permutation |= SHADERPERMUTATION_VIEWTINT;
1467         if (t)
1468                 permutation |= SHADERPERMUTATION_DIFFUSE;
1469         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1470                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1471         if (suppresstexalpha)
1472                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1473         if (vid.allowalphatocoverage)
1474                 GL_AlphaToCoverage(false);
1475         switch (vid.renderpath)
1476         {
1477         case RENDERPATH_GL32:
1478         case RENDERPATH_GLES2:
1479                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1480                 if (r_glsl_permutation->tex_Texture_First >= 0)
1481                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1482                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1483                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1484                 break;
1485         }
1486 }
1487
1488 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1489 {
1490         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1491 }
1492
1493 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1494 {
1495         uint64_t permutation = 0;
1496         if (r_trippy.integer && !notrippy)
1497                 permutation |= SHADERPERMUTATION_TRIPPY;
1498         if (depthrgb)
1499                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1500         if (skeletal)
1501                 permutation |= SHADERPERMUTATION_SKELETAL;
1502
1503         if (vid.allowalphatocoverage)
1504                 GL_AlphaToCoverage(false);
1505         switch (vid.renderpath)
1506         {
1507         case RENDERPATH_GL32:
1508         case RENDERPATH_GLES2:
1509                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1510 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1511                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1512 #endif
1513                 break;
1514         }
1515 }
1516
1517 #define BLENDFUNC_ALLOWS_COLORMOD      1
1518 #define BLENDFUNC_ALLOWS_FOG           2
1519 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1520 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1521 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1522 static int R_BlendFuncFlags(int src, int dst)
1523 {
1524         int r = 0;
1525
1526         // a blendfunc allows colormod if:
1527         // a) it can never keep the destination pixel invariant, or
1528         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1529         // this is to prevent unintended side effects from colormod
1530
1531         // a blendfunc allows fog if:
1532         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1533         // this is to prevent unintended side effects from fog
1534
1535         // these checks are the output of fogeval.pl
1536
1537         r |= BLENDFUNC_ALLOWS_COLORMOD;
1538         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1539         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1540         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1541         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1542         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1543         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1544         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1545         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1546         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1547         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1548         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1549         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1550         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1551         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1552         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1553         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1554         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1555         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1556         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1557         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1558         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559
1560         return r;
1561 }
1562
1563 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qbool notrippy, qbool ui)
1564 {
1565         // select a permutation of the lighting shader appropriate to this
1566         // combination of texture, entity, light source, and fogging, only use the
1567         // minimum features necessary to avoid wasting rendering time in the
1568         // fragment shader on features that are not being used
1569         uint64_t permutation = 0;
1570         unsigned int mode = 0;
1571         int blendfuncflags;
1572         texture_t *t = rsurface.texture;
1573         float m16f[16];
1574         matrix4x4_t tempmatrix;
1575         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1576         if (r_trippy.integer && !notrippy)
1577                 permutation |= SHADERPERMUTATION_TRIPPY;
1578         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1579                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1580         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1581                 permutation |= SHADERPERMUTATION_OCCLUDE;
1582         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1583                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1584         if (rsurfacepass == RSURFPASS_BACKGROUND)
1585         {
1586                 // distorted background
1587                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1588                 {
1589                         mode = SHADERMODE_WATER;
1590                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1591                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1592                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1593                         {
1594                                 // this is the right thing to do for wateralpha
1595                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1596                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1597                         }
1598                         else
1599                         {
1600                                 // this is the right thing to do for entity alpha
1601                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1602                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1603                         }
1604                 }
1605                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1606                 {
1607                         mode = SHADERMODE_REFRACTION;
1608                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1609                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1610                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1611                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1612                 }
1613                 else
1614                 {
1615                         mode = SHADERMODE_GENERIC;
1616                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1617                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1619                 }
1620                 if (vid.allowalphatocoverage)
1621                         GL_AlphaToCoverage(false);
1622         }
1623         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1624         {
1625                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1626                 {
1627                         switch(t->offsetmapping)
1628                         {
1629                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1630                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1631                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1632                         case OFFSETMAPPING_OFF: break;
1633                         }
1634                 }
1635                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1636                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1637                 // normalmap (deferred prepass), may use alpha test on diffuse
1638                 mode = SHADERMODE_DEFERREDGEOMETRY;
1639                 GL_BlendFunc(GL_ONE, GL_ZERO);
1640                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1641                 if (vid.allowalphatocoverage)
1642                         GL_AlphaToCoverage(false);
1643         }
1644         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1645         {
1646                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1647                 {
1648                         switch(t->offsetmapping)
1649                         {
1650                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1651                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1652                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1653                         case OFFSETMAPPING_OFF: break;
1654                         }
1655                 }
1656                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1657                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1658                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1659                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1660                 // light source
1661                 mode = SHADERMODE_LIGHTSOURCE;
1662                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1663                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1664                 if (VectorLength2(rtlightdiffuse) > 0)
1665                         permutation |= SHADERPERMUTATION_DIFFUSE;
1666                 if (VectorLength2(rtlightspecular) > 0)
1667                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1668                 if (r_refdef.fogenabled)
1669                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1670                 if (t->colormapping)
1671                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1672                 if (r_shadow_usingshadowmap2d)
1673                 {
1674                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1675                         if(r_shadow_shadowmapvsdct)
1676                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1677
1678                         if (r_shadow_shadowmap2ddepthbuffer)
1679                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1680                 }
1681                 if (t->reflectmasktexture)
1682                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1683                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1684                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1685                 if (vid.allowalphatocoverage)
1686                         GL_AlphaToCoverage(false);
1687         }
1688         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1689         {
1690                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1691                 {
1692                         switch(t->offsetmapping)
1693                         {
1694                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1695                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1696                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1697                         case OFFSETMAPPING_OFF: break;
1698                         }
1699                 }
1700                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1701                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1702                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1703                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1704                 // directional model lighting
1705                 mode = SHADERMODE_LIGHTGRID;
1706                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1707                         permutation |= SHADERPERMUTATION_GLOW;
1708                 permutation |= SHADERPERMUTATION_DIFFUSE;
1709                 if (t->glosstexture || t->backgroundglosstexture)
1710                         permutation |= SHADERPERMUTATION_SPECULAR;
1711                 if (r_refdef.fogenabled)
1712                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1713                 if (t->colormapping)
1714                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1715                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1716                 {
1717                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1718                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1719
1720                         if (r_shadow_shadowmap2ddepthbuffer)
1721                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1722                 }
1723                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1724                         permutation |= SHADERPERMUTATION_REFLECTION;
1725                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1726                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1727                 if (t->reflectmasktexture)
1728                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1729                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1730                 {
1731                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1732                         if (r_shadow_bouncegrid_state.directional)
1733                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1734                 }
1735                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1736                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1737                 // when using alphatocoverage, we don't need alphakill
1738                 if (vid.allowalphatocoverage)
1739                 {
1740                         if (r_transparent_alphatocoverage.integer)
1741                         {
1742                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1743                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1744                         }
1745                         else
1746                                 GL_AlphaToCoverage(false);
1747                 }
1748         }
1749         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1750         {
1751                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1752                 {
1753                         switch(t->offsetmapping)
1754                         {
1755                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1756                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1757                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1758                         case OFFSETMAPPING_OFF: break;
1759                         }
1760                 }
1761                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1762                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1763                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1764                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1765                 // directional model lighting
1766                 mode = SHADERMODE_LIGHTDIRECTION;
1767                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1768                         permutation |= SHADERPERMUTATION_GLOW;
1769                 if (VectorLength2(t->render_modellight_diffuse))
1770                         permutation |= SHADERPERMUTATION_DIFFUSE;
1771                 if (VectorLength2(t->render_modellight_specular) > 0)
1772                         permutation |= SHADERPERMUTATION_SPECULAR;
1773                 if (r_refdef.fogenabled)
1774                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1775                 if (t->colormapping)
1776                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1777                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1778                 {
1779                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1780                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1781
1782                         if (r_shadow_shadowmap2ddepthbuffer)
1783                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1784                 }
1785                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1786                         permutation |= SHADERPERMUTATION_REFLECTION;
1787                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1788                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1789                 if (t->reflectmasktexture)
1790                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1791                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1792                 {
1793                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1794                         if (r_shadow_bouncegrid_state.directional)
1795                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1796                 }
1797                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1798                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1799                 // when using alphatocoverage, we don't need alphakill
1800                 if (vid.allowalphatocoverage)
1801                 {
1802                         if (r_transparent_alphatocoverage.integer)
1803                         {
1804                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1805                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1806                         }
1807                         else
1808                                 GL_AlphaToCoverage(false);
1809                 }
1810         }
1811         else
1812         {
1813                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1814                 {
1815                         switch(t->offsetmapping)
1816                         {
1817                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1818                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1819                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1820                         case OFFSETMAPPING_OFF: break;
1821                         }
1822                 }
1823                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1824                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1825                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1826                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1827                 // lightmapped wall
1828                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1829                         permutation |= SHADERPERMUTATION_GLOW;
1830                 if (r_refdef.fogenabled && !ui)
1831                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1832                 if (t->colormapping)
1833                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1834                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1835                 {
1836                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1837                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1838
1839                         if (r_shadow_shadowmap2ddepthbuffer)
1840                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1841                 }
1842                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1843                         permutation |= SHADERPERMUTATION_REFLECTION;
1844                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1845                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1846                 if (t->reflectmasktexture)
1847                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1848                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1849                 {
1850                         // deluxemapping (light direction texture)
1851                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1852                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1853                         else
1854                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1855                         permutation |= SHADERPERMUTATION_DIFFUSE;
1856                         if (VectorLength2(t->render_lightmap_specular) > 0)
1857                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1858                 }
1859                 else if (r_glsl_deluxemapping.integer >= 2)
1860                 {
1861                         // fake deluxemapping (uniform light direction in tangentspace)
1862                         if (rsurface.uselightmaptexture)
1863                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1864                         else
1865                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1866                         permutation |= SHADERPERMUTATION_DIFFUSE;
1867                         if (VectorLength2(t->render_lightmap_specular) > 0)
1868                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1869                 }
1870                 else if (rsurface.uselightmaptexture)
1871                 {
1872                         // ordinary lightmapping (q1bsp, q3bsp)
1873                         mode = SHADERMODE_LIGHTMAP;
1874                 }
1875                 else
1876                 {
1877                         // ordinary vertex coloring (q3bsp)
1878                         mode = SHADERMODE_VERTEXCOLOR;
1879                 }
1880                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1881                 {
1882                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1883                         if (r_shadow_bouncegrid_state.directional)
1884                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1885                 }
1886                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1887                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1888                 // when using alphatocoverage, we don't need alphakill
1889                 if (vid.allowalphatocoverage)
1890                 {
1891                         if (r_transparent_alphatocoverage.integer)
1892                         {
1893                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1894                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1895                         }
1896                         else
1897                                 GL_AlphaToCoverage(false);
1898                 }
1899         }
1900         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1901                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1902         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1903                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1904         switch(vid.renderpath)
1905         {
1906         case RENDERPATH_GL32:
1907         case RENDERPATH_GLES2:
1908                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1909                 RSurf_UploadBuffersForBatch();
1910                 // this has to be after RSurf_PrepareVerticesForBatch
1911                 if (rsurface.batchskeletaltransform3x4buffer)
1912                         permutation |= SHADERPERMUTATION_SKELETAL;
1913                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1914 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1915                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1916 #endif
1917                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1918                 if (mode == SHADERMODE_LIGHTSOURCE)
1919                 {
1920                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1921                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1922                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1923                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1924                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1925                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1926
1927                         // additive passes are only darkened by fog, not tinted
1928                         if (r_glsl_permutation->loc_FogColor >= 0)
1929                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1930                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1931                 }
1932                 else
1933                 {
1934                         if (mode == SHADERMODE_FLATCOLOR)
1935                         {
1936                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1937                         }
1938                         else if (mode == SHADERMODE_LIGHTGRID)
1939                         {
1940                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1941                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1942                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1943                                 // other LightGrid uniforms handled below
1944                         }
1945                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1946                         {
1947                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1948                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1949                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1950                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1951                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1952                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1953                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir_local[0], t->render_modellight_lightdir_local[1], t->render_modellight_lightdir_local[2]);
1954                         }
1955                         else
1956                         {
1957                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1958                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1959                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1960                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1961                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1962                         }
1963                         // additive passes are only darkened by fog, not tinted
1964                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1965                         {
1966                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1967                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1968                                 else
1969                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1970                         }
1971                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1972                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1973                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1974                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1975                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1976                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1977                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1978                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1979                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1980                 }
1981                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1982                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1983                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1984                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1985                 {
1986                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1987                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1988                 }
1989                 else
1990                 {
1991                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1992                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1993                 }
1994
1995                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1996                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1997                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1998                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1999                 {
2000                         if (t->pantstexture)
2001                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2002                         else
2003                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2004                 }
2005                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2006                 {
2007                         if (t->shirttexture)
2008                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2009                         else
2010                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2011                 }
2012                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
2013                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2014                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2015                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2016                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2017                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2018                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2019                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2020                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2021                         );
2022                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
2023                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2024                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2025                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2026                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
2027                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2028                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2029                 {
2030                         float m9f[9];
2031                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2032                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2033                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2034                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2035                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2036                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2037                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2038                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2039                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2040                 }
2041
2042                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2043                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2044                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2045                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2046                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2047                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2048                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2049                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2050                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2051                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2052                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2053                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2054                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2055                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2056                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2057                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2058                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2059                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2060                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2061                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2062                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2063                 {
2064                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
2065                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
2066                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2067                 }
2068                 else
2069                 {
2070                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2071                 }
2072                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2073                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2074                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2075                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2076                 {
2077                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2078                         if (rsurface.rtlight)
2079                         {
2080                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2081                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2082                         }
2083                 }
2084                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2085                 if (r_glsl_permutation->tex_Texture_LightGrid   >= 0 && r_refdef.scene.worldmodel) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LightGrid, r_refdef.scene.worldmodel->brushq3.lightgridtexture);
2086                 CHECKGLERROR
2087                 break;
2088         }
2089 }
2090
2091 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2092 {
2093         // select a permutation of the lighting shader appropriate to this
2094         // combination of texture, entity, light source, and fogging, only use the
2095         // minimum features necessary to avoid wasting rendering time in the
2096         // fragment shader on features that are not being used
2097         uint64_t permutation = 0;
2098         unsigned int mode = 0;
2099         const float *lightcolorbase = rtlight->currentcolor;
2100         float ambientscale = rtlight->ambientscale;
2101         float diffusescale = rtlight->diffusescale;
2102         float specularscale = rtlight->specularscale;
2103         // this is the location of the light in view space
2104         vec3_t viewlightorigin;
2105         // this transforms from view space (camera) to light space (cubemap)
2106         matrix4x4_t viewtolight;
2107         matrix4x4_t lighttoview;
2108         float viewtolight16f[16];
2109         // light source
2110         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2111         if (rtlight->currentcubemap != r_texture_whitecube)
2112                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2113         if (diffusescale > 0)
2114                 permutation |= SHADERPERMUTATION_DIFFUSE;
2115         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2116                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2117         if (r_shadow_usingshadowmap2d)
2118         {
2119                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2120                 if (r_shadow_shadowmapvsdct)
2121                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2122
2123                 if (r_shadow_shadowmap2ddepthbuffer)
2124                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2125         }
2126         if (vid.allowalphatocoverage)
2127                 GL_AlphaToCoverage(false);
2128         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2129         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2130         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2131         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2132         switch(vid.renderpath)
2133         {
2134         case RENDERPATH_GL32:
2135         case RENDERPATH_GLES2:
2136                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2137                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2138                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2139                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2140                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2141                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2142                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2143                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2144                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2145                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2146                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2147
2148                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2149                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2150                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2151                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2152                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2153                 break;
2154         }
2155 }
2156
2157 #define SKINFRAME_HASH 1024
2158
2159 typedef struct
2160 {
2161         unsigned int loadsequence; // incremented each level change
2162         memexpandablearray_t array;
2163         skinframe_t *hash[SKINFRAME_HASH];
2164 }
2165 r_skinframe_t;
2166 r_skinframe_t r_skinframe;
2167
2168 void R_SkinFrame_PrepareForPurge(void)
2169 {
2170         r_skinframe.loadsequence++;
2171         // wrap it without hitting zero
2172         if (r_skinframe.loadsequence >= 200)
2173                 r_skinframe.loadsequence = 1;
2174 }
2175
2176 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2177 {
2178         if (!skinframe)
2179                 return;
2180         // mark the skinframe as used for the purging code
2181         skinframe->loadsequence = r_skinframe.loadsequence;
2182 }
2183
2184 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2185 {
2186         if (s == NULL)
2187                 return;
2188         if (s->merged == s->base)
2189                 s->merged = NULL;
2190         R_PurgeTexture(s->stain); s->stain = NULL;
2191         R_PurgeTexture(s->merged); s->merged = NULL;
2192         R_PurgeTexture(s->base); s->base = NULL;
2193         R_PurgeTexture(s->pants); s->pants = NULL;
2194         R_PurgeTexture(s->shirt); s->shirt = NULL;
2195         R_PurgeTexture(s->nmap); s->nmap = NULL;
2196         R_PurgeTexture(s->gloss); s->gloss = NULL;
2197         R_PurgeTexture(s->glow); s->glow = NULL;
2198         R_PurgeTexture(s->fog); s->fog = NULL;
2199         R_PurgeTexture(s->reflect); s->reflect = NULL;
2200         s->loadsequence = 0;
2201 }
2202
2203 void R_SkinFrame_Purge(void)
2204 {
2205         int i;
2206         skinframe_t *s;
2207         for (i = 0;i < SKINFRAME_HASH;i++)
2208         {
2209                 for (s = r_skinframe.hash[i];s;s = s->next)
2210                 {
2211                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2212                                 R_SkinFrame_PurgeSkinFrame(s);
2213                 }
2214         }
2215 }
2216
2217 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2218         skinframe_t *item;
2219         char basename[MAX_QPATH];
2220
2221         Image_StripImageExtension(name, basename, sizeof(basename));
2222
2223         if( last == NULL ) {
2224                 int hashindex;
2225                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2226                 item = r_skinframe.hash[hashindex];
2227         } else {
2228                 item = last->next;
2229         }
2230
2231         // linearly search through the hash bucket
2232         for( ; item ; item = item->next ) {
2233                 if( !strcmp( item->basename, basename ) ) {
2234                         return item;
2235                 }
2236         }
2237         return NULL;
2238 }
2239
2240 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2241 {
2242         skinframe_t *item;
2243         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2244         int hashindex;
2245         char basename[MAX_QPATH];
2246
2247         Image_StripImageExtension(name, basename, sizeof(basename));
2248
2249         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2250         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2251                 if (!strcmp(item->basename, basename) &&
2252                         item->textureflags == compareflags &&
2253                         item->comparewidth == comparewidth &&
2254                         item->compareheight == compareheight &&
2255                         item->comparecrc == comparecrc)
2256                         break;
2257
2258         if (!item)
2259         {
2260                 if (!add)
2261                         return NULL;
2262                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2263                 memset(item, 0, sizeof(*item));
2264                 dp_strlcpy(item->basename, basename, sizeof(item->basename));
2265                 item->textureflags = compareflags;
2266                 item->comparewidth = comparewidth;
2267                 item->compareheight = compareheight;
2268                 item->comparecrc = comparecrc;
2269                 item->next = r_skinframe.hash[hashindex];
2270                 r_skinframe.hash[hashindex] = item;
2271         }
2272         else if (textureflags & TEXF_FORCE_RELOAD)
2273                 R_SkinFrame_PurgeSkinFrame(item);
2274
2275         R_SkinFrame_MarkUsed(item);
2276         return item;
2277 }
2278
2279 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2280         { \
2281                 unsigned long long avgcolor[5], wsum; \
2282                 int pix, comp, w; \
2283                 avgcolor[0] = 0; \
2284                 avgcolor[1] = 0; \
2285                 avgcolor[2] = 0; \
2286                 avgcolor[3] = 0; \
2287                 avgcolor[4] = 0; \
2288                 wsum = 0; \
2289                 for(pix = 0; pix < cnt; ++pix) \
2290                 { \
2291                         w = 0; \
2292                         for(comp = 0; comp < 3; ++comp) \
2293                                 w += getpixel; \
2294                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2295                         { \
2296                                 ++wsum; \
2297                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2298                                 w = getpixel; \
2299                                 for(comp = 0; comp < 3; ++comp) \
2300                                         avgcolor[comp] += getpixel * w; \
2301                                 avgcolor[3] += w; \
2302                         } \
2303                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2304                         avgcolor[4] += getpixel; \
2305                 } \
2306                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2307                         avgcolor[3] = 1; \
2308                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2309                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2310                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2311                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2312         }
2313
2314 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2315 {
2316         skinframe_t *skinframe;
2317
2318         if (cls.state == ca_dedicated)
2319                 return NULL;
2320
2321         // return an existing skinframe if already loaded
2322         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2323         if (skinframe && skinframe->base)
2324                 return skinframe;
2325
2326         // if the skinframe doesn't exist this will create it
2327         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2328 }
2329
2330 extern cvar_t gl_picmip;
2331 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2332 {
2333         int j;
2334         unsigned char *pixels;
2335         unsigned char *bumppixels;
2336         unsigned char *basepixels = NULL;
2337         int basepixels_width = 0;
2338         int basepixels_height = 0;
2339         rtexture_t *ddsbase = NULL;
2340         qbool ddshasalpha = false;
2341         float ddsavgcolor[4];
2342         char basename[MAX_QPATH];
2343         int miplevel = R_PicmipForFlags(textureflags);
2344         int savemiplevel = miplevel;
2345         int mymiplevel;
2346         char vabuf[1024];
2347
2348         if (cls.state == ca_dedicated)
2349                 return NULL;
2350
2351         Image_StripImageExtension(name, basename, sizeof(basename));
2352
2353         // check for DDS texture file first
2354         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2355         {
2356                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2357                 if (basepixels == NULL && fallbacknotexture)
2358                         basepixels = Image_GenerateNoTexture();
2359                 if (basepixels == NULL)
2360                         return NULL;
2361         }
2362
2363         // FIXME handle miplevel
2364
2365         if (developer_loading.integer)
2366                 Con_Printf("loading skin \"%s\"\n", name);
2367
2368         // we've got some pixels to store, so really allocate this new texture now
2369         if (!skinframe)
2370                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2371         textureflags &= ~TEXF_FORCE_RELOAD;
2372         skinframe->stain = NULL;
2373         skinframe->merged = NULL;
2374         skinframe->base = NULL;
2375         skinframe->pants = NULL;
2376         skinframe->shirt = NULL;
2377         skinframe->nmap = NULL;
2378         skinframe->gloss = NULL;
2379         skinframe->glow = NULL;
2380         skinframe->fog = NULL;
2381         skinframe->reflect = NULL;
2382         skinframe->hasalpha = false;
2383         // we could store the q2animname here too
2384
2385         if (ddsbase)
2386         {
2387                 skinframe->base = ddsbase;
2388                 skinframe->hasalpha = ddshasalpha;
2389                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2390                 if (r_loadfog && skinframe->hasalpha)
2391                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2392                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2393         }
2394         else
2395         {
2396                 basepixels_width = image_width;
2397                 basepixels_height = image_height;
2398                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2399                 if (textureflags & TEXF_ALPHA)
2400                 {
2401                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2402                         {
2403                                 if (basepixels[j] < 255)
2404                                 {
2405                                         skinframe->hasalpha = true;
2406                                         break;
2407                                 }
2408                         }
2409                         if (r_loadfog && skinframe->hasalpha)
2410                         {
2411                                 // has transparent pixels
2412                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2413                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2414                                 {
2415                                         pixels[j+0] = 255;
2416                                         pixels[j+1] = 255;
2417                                         pixels[j+2] = 255;
2418                                         pixels[j+3] = basepixels[j+3];
2419                                 }
2420                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2421                                 Mem_Free(pixels);
2422                         }
2423                 }
2424                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2425 #ifndef USE_GLES2
2426                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2427                 if (r_savedds && skinframe->base)
2428                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2429                 if (r_savedds && skinframe->fog)
2430                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2431 #endif
2432         }
2433
2434         if (r_loaddds)
2435         {
2436                 mymiplevel = savemiplevel;
2437                 if (r_loadnormalmap)
2438                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2439                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2440                 if (r_loadgloss)
2441                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2442                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2443                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2444                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2445         }
2446
2447         // _norm is the name used by tenebrae and has been adopted as standard
2448         if (r_loadnormalmap && skinframe->nmap == NULL)
2449         {
2450                 mymiplevel = savemiplevel;
2451                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2452                 {
2453                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2454                         Mem_Free(pixels);
2455                         pixels = NULL;
2456                 }
2457                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2458                 {
2459                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2460                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2461                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2462                         Mem_Free(pixels);
2463                         Mem_Free(bumppixels);
2464                 }
2465                 else if (r_shadow_bumpscale_basetexture.value > 0)
2466                 {
2467                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2468                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2469                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2470                         Mem_Free(pixels);
2471                 }
2472 #ifndef USE_GLES2
2473                 if (r_savedds && skinframe->nmap)
2474                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2475 #endif
2476         }
2477
2478         // _luma is supported only for tenebrae compatibility
2479         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2480         // _glow is the preferred name
2481         mymiplevel = savemiplevel;
2482         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s.blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2483         {
2484                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2485 #ifndef USE_GLES2
2486                 if (r_savedds && skinframe->glow)
2487                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2488 #endif
2489                 Mem_Free(pixels);pixels = NULL;
2490         }
2491
2492         mymiplevel = savemiplevel;
2493         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2494         {
2495                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2496 #ifndef USE_GLES2
2497                 if (r_savedds && skinframe->gloss)
2498                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2499 #endif
2500                 Mem_Free(pixels);
2501                 pixels = NULL;
2502         }
2503
2504         mymiplevel = savemiplevel;
2505         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2506         {
2507                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2508 #ifndef USE_GLES2
2509                 if (r_savedds && skinframe->pants)
2510                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2511 #endif
2512                 Mem_Free(pixels);
2513                 pixels = NULL;
2514         }
2515
2516         mymiplevel = savemiplevel;
2517         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2518         {
2519                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2520 #ifndef USE_GLES2
2521                 if (r_savedds && skinframe->shirt)
2522                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2523 #endif
2524                 Mem_Free(pixels);
2525                 pixels = NULL;
2526         }
2527
2528         mymiplevel = savemiplevel;
2529         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2530         {
2531                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2532 #ifndef USE_GLES2
2533                 if (r_savedds && skinframe->reflect)
2534                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2535 #endif
2536                 Mem_Free(pixels);
2537                 pixels = NULL;
2538         }
2539
2540         if (basepixels)
2541                 Mem_Free(basepixels);
2542
2543         return skinframe;
2544 }
2545
2546 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qbool sRGB)
2547 {
2548         int i;
2549         skinframe_t *skinframe;
2550         char vabuf[1024];
2551
2552         if (cls.state == ca_dedicated)
2553                 return NULL;
2554
2555         // if already loaded just return it, otherwise make a new skinframe
2556         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2557         if (skinframe->base)
2558                 return skinframe;
2559         textureflags &= ~TEXF_FORCE_RELOAD;
2560
2561         skinframe->stain = NULL;
2562         skinframe->merged = NULL;
2563         skinframe->base = NULL;
2564         skinframe->pants = NULL;
2565         skinframe->shirt = NULL;
2566         skinframe->nmap = NULL;
2567         skinframe->gloss = NULL;
2568         skinframe->glow = NULL;
2569         skinframe->fog = NULL;
2570         skinframe->reflect = NULL;
2571         skinframe->hasalpha = false;
2572
2573         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2574         if (!skindata)
2575                 return NULL;
2576
2577         if (developer_loading.integer)
2578                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2579
2580         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2581         {
2582                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2583                 unsigned char *b = a + width * height * 4;
2584                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2585                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2586                 Mem_Free(a);
2587         }
2588         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2589         if (textureflags & TEXF_ALPHA)
2590         {
2591                 for (i = 3;i < width * height * 4;i += 4)
2592                 {
2593                         if (skindata[i] < 255)
2594                         {
2595                                 skinframe->hasalpha = true;
2596                                 break;
2597                         }
2598                 }
2599                 if (r_loadfog && skinframe->hasalpha)
2600                 {
2601                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2602                         memcpy(fogpixels, skindata, width * height * 4);
2603                         for (i = 0;i < width * height * 4;i += 4)
2604                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2605                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2606                         Mem_Free(fogpixels);
2607                 }
2608         }
2609
2610         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2611         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2612
2613         return skinframe;
2614 }
2615
2616 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2617 {
2618         int i;
2619         int featuresmask;
2620         skinframe_t *skinframe;
2621
2622         if (cls.state == ca_dedicated)
2623                 return NULL;
2624
2625         // if already loaded just return it, otherwise make a new skinframe
2626         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2627         if (skinframe->base)
2628                 return skinframe;
2629         //textureflags &= ~TEXF_FORCE_RELOAD;
2630
2631         skinframe->stain = NULL;
2632         skinframe->merged = NULL;
2633         skinframe->base = NULL;
2634         skinframe->pants = NULL;
2635         skinframe->shirt = NULL;
2636         skinframe->nmap = NULL;
2637         skinframe->gloss = NULL;
2638         skinframe->glow = NULL;
2639         skinframe->fog = NULL;
2640         skinframe->reflect = NULL;
2641         skinframe->hasalpha = false;
2642
2643         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2644         if (!skindata)
2645                 return NULL;
2646
2647         if (developer_loading.integer)
2648                 Con_Printf("loading quake skin \"%s\"\n", name);
2649
2650         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2651         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2652         memcpy(skinframe->qpixels, skindata, width*height);
2653         skinframe->qwidth = width;
2654         skinframe->qheight = height;
2655
2656         featuresmask = 0;
2657         for (i = 0;i < width * height;i++)
2658                 featuresmask |= palette_featureflags[skindata[i]];
2659
2660         skinframe->hasalpha = false;
2661         // fence textures
2662         if (name[0] == '{')
2663                 skinframe->hasalpha = true;
2664         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2665         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2666         skinframe->qgeneratemerged = true;
2667         skinframe->qgeneratebase = skinframe->qhascolormapping;
2668         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2669
2670         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2671         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2672
2673         return skinframe;
2674 }
2675
2676 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2677 {
2678         int width;
2679         int height;
2680         unsigned char *skindata;
2681         char vabuf[1024];
2682
2683         if (!skinframe->qpixels)
2684                 return;
2685
2686         if (!skinframe->qhascolormapping)
2687                 colormapped = false;
2688
2689         if (colormapped)
2690         {
2691                 if (!skinframe->qgeneratebase)
2692                         return;
2693         }
2694         else
2695         {
2696                 if (!skinframe->qgeneratemerged)
2697                         return;
2698         }
2699
2700         width = skinframe->qwidth;
2701         height = skinframe->qheight;
2702         skindata = skinframe->qpixels;
2703
2704         if (skinframe->qgeneratenmap)
2705         {
2706                 unsigned char *a, *b;
2707                 skinframe->qgeneratenmap = false;
2708                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2709                 b = a + width * height * 4;
2710                 // use either a custom palette or the quake palette
2711                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2712                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2713                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2714                 Mem_Free(a);
2715         }
2716
2717         if (skinframe->qgenerateglow)
2718         {
2719                 skinframe->qgenerateglow = false;
2720                 if (skinframe->hasalpha) // fence textures
2721                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2722                 else
2723                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2724         }
2725
2726         if (colormapped)
2727         {
2728                 skinframe->qgeneratebase = false;
2729                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2730                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2731                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2732         }
2733         else
2734         {
2735                 skinframe->qgeneratemerged = false;
2736                 if (skinframe->hasalpha) // fence textures
2737                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2738                 else
2739                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2740         }
2741
2742         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2743         {
2744                 Mem_Free(skinframe->qpixels);
2745                 skinframe->qpixels = NULL;
2746         }
2747 }
2748
2749 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2750 {
2751         int i;
2752         skinframe_t *skinframe;
2753         char vabuf[1024];
2754
2755         if (cls.state == ca_dedicated)
2756                 return NULL;
2757
2758         // if already loaded just return it, otherwise make a new skinframe
2759         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2760         if (skinframe->base)
2761                 return skinframe;
2762         textureflags &= ~TEXF_FORCE_RELOAD;
2763
2764         skinframe->stain = NULL;
2765         skinframe->merged = NULL;
2766         skinframe->base = NULL;
2767         skinframe->pants = NULL;
2768         skinframe->shirt = NULL;
2769         skinframe->nmap = NULL;
2770         skinframe->gloss = NULL;
2771         skinframe->glow = NULL;
2772         skinframe->fog = NULL;
2773         skinframe->reflect = NULL;
2774         skinframe->hasalpha = false;
2775
2776         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2777         if (!skindata)
2778                 return NULL;
2779
2780         if (developer_loading.integer)
2781                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2782
2783         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2784         if ((textureflags & TEXF_ALPHA) && alphapalette)
2785         {
2786                 for (i = 0;i < width * height;i++)
2787                 {
2788                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2789                         {
2790                                 skinframe->hasalpha = true;
2791                                 break;
2792                         }
2793                 }
2794                 if (r_loadfog && skinframe->hasalpha)
2795                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2796         }
2797
2798         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2799         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2800
2801         return skinframe;
2802 }
2803
2804 skinframe_t *R_SkinFrame_LoadMissing(void)
2805 {
2806         skinframe_t *skinframe;
2807
2808         if (cls.state == ca_dedicated)
2809                 return NULL;
2810
2811         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2812         skinframe->stain = NULL;
2813         skinframe->merged = NULL;
2814         skinframe->base = NULL;
2815         skinframe->pants = NULL;
2816         skinframe->shirt = NULL;
2817         skinframe->nmap = NULL;
2818         skinframe->gloss = NULL;
2819         skinframe->glow = NULL;
2820         skinframe->fog = NULL;
2821         skinframe->reflect = NULL;
2822         skinframe->hasalpha = false;
2823
2824         skinframe->avgcolor[0] = rand() / RAND_MAX;
2825         skinframe->avgcolor[1] = rand() / RAND_MAX;
2826         skinframe->avgcolor[2] = rand() / RAND_MAX;
2827         skinframe->avgcolor[3] = 1;
2828
2829         return skinframe;
2830 }
2831
2832 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2833 {
2834         if (cls.state == ca_dedicated)
2835                 return NULL;
2836
2837         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2838 }
2839
2840 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2841 {
2842         skinframe_t *skinframe;
2843         if (cls.state == ca_dedicated)
2844                 return NULL;
2845         // if already loaded just return it, otherwise make a new skinframe
2846         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2847         if (skinframe->base)
2848                 return skinframe;
2849         textureflags &= ~TEXF_FORCE_RELOAD;
2850         skinframe->stain = NULL;
2851         skinframe->merged = NULL;
2852         skinframe->base = NULL;
2853         skinframe->pants = NULL;
2854         skinframe->shirt = NULL;
2855         skinframe->nmap = NULL;
2856         skinframe->gloss = NULL;
2857         skinframe->glow = NULL;
2858         skinframe->fog = NULL;
2859         skinframe->reflect = NULL;
2860         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2861         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2862         if (!tex)
2863                 return NULL;
2864         if (developer_loading.integer)
2865                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2866         skinframe->base = skinframe->merged = tex;
2867         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2868         return skinframe;
2869 }
2870
2871 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2872 typedef struct suffixinfo_s
2873 {
2874         const char *suffix;
2875         qbool flipx, flipy, flipdiagonal;
2876 }
2877 suffixinfo_t;
2878 static suffixinfo_t suffix[3][6] =
2879 {
2880         {
2881                 {"px",   false, false, false},
2882                 {"nx",   false, false, false},
2883                 {"py",   false, false, false},
2884                 {"ny",   false, false, false},
2885                 {"pz",   false, false, false},
2886                 {"nz",   false, false, false}
2887         },
2888         {
2889                 {"posx", false, false, false},
2890                 {"negx", false, false, false},
2891                 {"posy", false, false, false},
2892                 {"negy", false, false, false},
2893                 {"posz", false, false, false},
2894                 {"negz", false, false, false}
2895         },
2896         {
2897                 {"rt",    true, false,  true},
2898                 {"lf",   false,  true,  true},
2899                 {"ft",    true,  true, false},
2900                 {"bk",   false, false, false},
2901                 {"up",    true, false,  true},
2902                 {"dn",    true, false,  true}
2903         }
2904 };
2905
2906 static int componentorder[4] = {0, 1, 2, 3};
2907
2908 static rtexture_t *R_LoadCubemap(const char *basename)
2909 {
2910         int i, j, cubemapsize, forcefilter;
2911         unsigned char *cubemappixels, *image_buffer;
2912         rtexture_t *cubemaptexture;
2913         char name[256];
2914
2915         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2916         forcefilter = TEXF_FORCELINEAR;
2917         if (basename && basename[0] == '!')
2918         {
2919                 basename++;
2920                 forcefilter = TEXF_FORCENEAREST;
2921         }
2922         // must start 0 so the first loadimagepixels has no requested width/height
2923         cubemapsize = 0;
2924         cubemappixels = NULL;
2925         cubemaptexture = NULL;
2926         // keep trying different suffix groups (posx, px, rt) until one loads
2927         for (j = 0;j < 3 && !cubemappixels;j++)
2928         {
2929                 // load the 6 images in the suffix group
2930                 for (i = 0;i < 6;i++)
2931                 {
2932                         // generate an image name based on the base and and suffix
2933                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2934                         // load it
2935                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2936                         {
2937                                 // an image loaded, make sure width and height are equal
2938                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2939                                 {
2940                                         // if this is the first image to load successfully, allocate the cubemap memory
2941                                         if (!cubemappixels && image_width >= 1)
2942                                         {
2943                                                 cubemapsize = image_width;
2944                                                 // note this clears to black, so unavailable sides are black
2945                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2946                                         }
2947                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2948                                         if (cubemappixels)
2949                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2950                                 }
2951                                 else
2952                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2953                                 // free the image
2954                                 Mem_Free(image_buffer);
2955                         }
2956                 }
2957         }
2958         // if a cubemap loaded, upload it
2959         if (cubemappixels)
2960         {
2961                 if (developer_loading.integer)
2962                         Con_Printf("loading cubemap \"%s\"\n", basename);
2963
2964                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | forcefilter | TEXF_CLAMP, -1, NULL);
2965                 Mem_Free(cubemappixels);
2966         }
2967         else
2968         {
2969                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2970                 if (developer_loading.integer)
2971                 {
2972                         Con_Printf("(tried tried images ");
2973                         for (j = 0;j < 3;j++)
2974                                 for (i = 0;i < 6;i++)
2975                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2976                         Con_Print(" and was unable to find any of them).\n");
2977                 }
2978         }
2979         return cubemaptexture;
2980 }
2981
2982 rtexture_t *R_GetCubemap(const char *basename)
2983 {
2984         int i;
2985         for (i = 0;i < r_texture_numcubemaps;i++)
2986                 if (r_texture_cubemaps[i] != NULL)
2987                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2988                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2989         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2990                 return r_texture_whitecube;
2991         r_texture_numcubemaps++;
2992         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2993         dp_strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2994         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2995         return r_texture_cubemaps[i]->texture;
2996 }
2997
2998 static void R_Main_FreeViewCache(void)
2999 {
3000         if (r_refdef.viewcache.entityvisible)
3001                 Mem_Free(r_refdef.viewcache.entityvisible);
3002         if (r_refdef.viewcache.world_pvsbits)
3003                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3004         if (r_refdef.viewcache.world_leafvisible)
3005                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3006         if (r_refdef.viewcache.world_surfacevisible)
3007                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3008         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3009 }
3010
3011 static void R_Main_ResizeViewCache(void)
3012 {
3013         int numentities = r_refdef.scene.numentities;
3014         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3015         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3016         if (r_refdef.viewcache.maxentities < numentities)
3017         {
3018                 r_refdef.viewcache.maxentities = numentities;
3019                 if (r_refdef.viewcache.entityvisible)
3020                         Mem_Free(r_refdef.viewcache.entityvisible);
3021                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3022         }
3023         // bones_was_here: r_refdef.viewcache.world_pvsbits was (re)allocated here, now done in Mod_BSP_FatPVS()
3024         if (r_refdef.viewcache.world_numleafs != numleafs)
3025         {
3026                 r_refdef.viewcache.world_numleafs = numleafs;
3027                 if (r_refdef.viewcache.world_leafvisible)
3028                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3029                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3030         }
3031         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3032         {
3033                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3034                 if (r_refdef.viewcache.world_surfacevisible)
3035                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3036                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3037         }
3038 }
3039
3040 extern rtexture_t *loadingscreentexture;
3041 static void gl_main_start(void)
3042 {
3043         loadingscreentexture = NULL;
3044         r_texture_blanknormalmap = NULL;
3045         r_texture_white = NULL;
3046         r_texture_grey128 = NULL;
3047         r_texture_black = NULL;
3048         r_texture_whitecube = NULL;
3049         r_texture_normalizationcube = NULL;
3050         r_texture_fogattenuation = NULL;
3051         r_texture_fogheighttexture = NULL;
3052         r_texture_gammaramps = NULL;
3053         r_texture_numcubemaps = 0;
3054         r_uniformbufferalignment = 32;
3055
3056         r_loaddds = r_texture_dds_load.integer != 0;
3057         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3058
3059         switch(vid.renderpath)
3060         {
3061         case RENDERPATH_GL32:
3062         case RENDERPATH_GLES2:
3063                 r_loadnormalmap = true;
3064                 r_loadgloss = true;
3065                 r_loadfog = false;
3066 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3067                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3068 #endif
3069                 break;
3070         }
3071
3072         R_AnimCache_Free();
3073         R_FrameData_Reset();
3074         R_BufferData_Reset();
3075
3076         r_numqueries = 0;
3077         r_maxqueries = 0;
3078         memset(r_queries, 0, sizeof(r_queries));
3079
3080         r_qwskincache = NULL;
3081         r_qwskincache_size = 0;
3082
3083         // due to caching of texture_t references, the collision cache must be reset
3084         Collision_Cache_Reset(true);
3085
3086         // set up r_skinframe loading system for textures
3087         memset(&r_skinframe, 0, sizeof(r_skinframe));
3088         r_skinframe.loadsequence = 1;
3089         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3090
3091         r_main_texturepool = R_AllocTexturePool();
3092         R_BuildBlankTextures();
3093         R_BuildNoTexture();
3094         R_BuildWhiteCube();
3095 #ifndef USE_GLES2
3096         R_BuildNormalizationCube();
3097 #endif //USE_GLES2
3098         r_texture_fogattenuation = NULL;
3099         r_texture_fogheighttexture = NULL;
3100         r_texture_gammaramps = NULL;
3101         //r_texture_fogintensity = NULL;
3102         memset(&r_fb, 0, sizeof(r_fb));
3103         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3104         r_glsl_permutation = NULL;
3105         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3106         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3107         memset(&r_svbsp, 0, sizeof (r_svbsp));
3108
3109         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3110         r_texture_numcubemaps = 0;
3111
3112         r_refdef.fogmasktable_density = 0;
3113
3114 #ifdef __ANDROID__
3115         // For Steelstorm Android
3116         // FIXME CACHE the program and reload
3117         // FIXME see possible combinations for SS:BR android
3118         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3119         R_SetupShader_SetPermutationGLSL(0, 12);
3120         R_SetupShader_SetPermutationGLSL(0, 13);
3121         R_SetupShader_SetPermutationGLSL(0, 8388621);
3122         R_SetupShader_SetPermutationGLSL(3, 0);
3123         R_SetupShader_SetPermutationGLSL(3, 2048);
3124         R_SetupShader_SetPermutationGLSL(5, 0);
3125         R_SetupShader_SetPermutationGLSL(5, 2);
3126         R_SetupShader_SetPermutationGLSL(5, 2048);
3127         R_SetupShader_SetPermutationGLSL(5, 8388608);
3128         R_SetupShader_SetPermutationGLSL(11, 1);
3129         R_SetupShader_SetPermutationGLSL(11, 2049);
3130         R_SetupShader_SetPermutationGLSL(11, 8193);
3131         R_SetupShader_SetPermutationGLSL(11, 10241);
3132         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3133 #endif
3134 }
3135
3136 extern unsigned int r_shadow_occlusion_buf;
3137
3138 static void gl_main_shutdown(void)
3139 {
3140         R_RenderTarget_FreeUnused(true);
3141         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3142         R_AnimCache_Free();
3143         R_FrameData_Reset();
3144         R_BufferData_Reset();
3145
3146         R_Main_FreeViewCache();
3147
3148         switch(vid.renderpath)
3149         {
3150         case RENDERPATH_GL32:
3151         case RENDERPATH_GLES2:
3152 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3153                 if (r_maxqueries)
3154                         qglDeleteQueries(r_maxqueries, r_queries);
3155 #endif
3156                 break;
3157         }
3158         r_shadow_occlusion_buf = 0;
3159         r_numqueries = 0;
3160         r_maxqueries = 0;
3161         memset(r_queries, 0, sizeof(r_queries));
3162
3163         r_qwskincache = NULL;
3164         r_qwskincache_size = 0;
3165
3166         // clear out the r_skinframe state
3167         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3168         memset(&r_skinframe, 0, sizeof(r_skinframe));
3169
3170         if (r_svbsp.nodes)
3171                 Mem_Free(r_svbsp.nodes);
3172         memset(&r_svbsp, 0, sizeof (r_svbsp));
3173         R_FreeTexturePool(&r_main_texturepool);
3174         loadingscreentexture = NULL;
3175         r_texture_blanknormalmap = NULL;
3176         r_texture_white = NULL;
3177         r_texture_grey128 = NULL;
3178         r_texture_black = NULL;
3179         r_texture_whitecube = NULL;
3180         r_texture_normalizationcube = NULL;
3181         r_texture_fogattenuation = NULL;
3182         r_texture_fogheighttexture = NULL;
3183         r_texture_gammaramps = NULL;
3184         r_texture_numcubemaps = 0;
3185         //r_texture_fogintensity = NULL;
3186         memset(&r_fb, 0, sizeof(r_fb));
3187         R_GLSL_Restart_f(cmd_local);
3188
3189         r_glsl_permutation = NULL;
3190         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3191         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3192 }
3193
3194 static void gl_main_newmap(void)
3195 {
3196         // FIXME: move this code to client
3197         char *entities, entname[MAX_QPATH];
3198         if (r_qwskincache)
3199                 Mem_Free(r_qwskincache);
3200         r_qwskincache = NULL;
3201         r_qwskincache_size = 0;
3202         if (cl.worldmodel)
3203         {
3204                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3205                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3206                 {
3207                         CL_ParseEntityLump(entities);
3208                         Mem_Free(entities);
3209                         return;
3210                 }
3211                 if (cl.worldmodel->brush.entities)
3212                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3213         }
3214         R_Main_FreeViewCache();
3215
3216         R_FrameData_Reset();
3217         R_BufferData_Reset();
3218 }
3219
3220 void GL_Main_Init(void)
3221 {
3222         int i;
3223         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3224         R_InitShaderModeInfo();
3225
3226         Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3227         Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3228         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3229         if (gamemode == GAME_NEHAHRA)
3230         {
3231                 Cvar_RegisterVariable (&gl_fogenable);
3232                 Cvar_RegisterVariable (&gl_fogdensity);
3233                 Cvar_RegisterVariable (&gl_fogred);
3234                 Cvar_RegisterVariable (&gl_foggreen);
3235                 Cvar_RegisterVariable (&gl_fogblue);
3236                 Cvar_RegisterVariable (&gl_fogstart);
3237                 Cvar_RegisterVariable (&gl_fogend);
3238                 Cvar_RegisterVariable (&gl_skyclip);
3239         }
3240         Cvar_RegisterVariable(&r_motionblur);
3241         Cvar_RegisterVariable(&r_damageblur);
3242         Cvar_RegisterVariable(&r_motionblur_averaging);
3243         Cvar_RegisterVariable(&r_motionblur_randomize);
3244         Cvar_RegisterVariable(&r_motionblur_minblur);
3245         Cvar_RegisterVariable(&r_motionblur_maxblur);
3246         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3247         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3248         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3249         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3250         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3251         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3252         Cvar_RegisterVariable(&r_depthfirst);
3253         Cvar_RegisterVariable(&r_useinfinitefarclip);
3254         Cvar_RegisterVariable(&r_farclip_base);
3255         Cvar_RegisterVariable(&r_farclip_world);
3256         Cvar_RegisterVariable(&r_nearclip);
3257         Cvar_RegisterVariable(&r_deformvertexes);
3258         Cvar_RegisterVariable(&r_transparent);
3259         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3260         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3261         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3262         Cvar_RegisterVariable(&r_showoverdraw);
3263         Cvar_RegisterVariable(&r_showbboxes);
3264         Cvar_RegisterVariable(&r_showbboxes_client);
3265         Cvar_RegisterVariable(&r_showsurfaces);
3266         Cvar_RegisterVariable(&r_showtris);
3267         Cvar_RegisterVariable(&r_shownormals);
3268         Cvar_RegisterVariable(&r_showlighting);
3269         Cvar_RegisterVariable(&r_showcollisionbrushes);
3270         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3271         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3272         Cvar_RegisterVariable(&r_showdisabledepthtest);
3273         Cvar_RegisterVariable(&r_showspriteedges);
3274         Cvar_RegisterVariable(&r_showparticleedges);
3275         Cvar_RegisterVariable(&r_drawportals);
3276         Cvar_RegisterVariable(&r_drawentities);
3277         Cvar_RegisterVariable(&r_draw2d);
3278         Cvar_RegisterVariable(&r_drawworld);
3279         Cvar_RegisterVariable(&r_cullentities_trace);
3280         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3281         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3282         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3283         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3284         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3285         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3286         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3287         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3288         Cvar_RegisterVariable(&r_sortentities);
3289         Cvar_RegisterVariable(&r_drawviewmodel);
3290         Cvar_RegisterVariable(&r_drawexteriormodel);
3291         Cvar_RegisterVariable(&r_speeds);
3292         Cvar_RegisterVariable(&r_fullbrights);
3293         Cvar_RegisterVariable(&r_wateralpha);
3294         Cvar_RegisterVariable(&r_dynamic);
3295         Cvar_RegisterVariable(&r_fullbright_directed);
3296         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3297         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3298         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3299         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3300         Cvar_RegisterVariable(&r_fullbright);
3301         Cvar_RegisterVariable(&r_shadows);
3302         Cvar_RegisterVariable(&r_shadows_darken);
3303         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3304         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3305         Cvar_RegisterVariable(&r_shadows_throwdistance);
3306         Cvar_RegisterVariable(&r_shadows_throwdirection);
3307         Cvar_RegisterVariable(&r_shadows_focus);
3308         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3309         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3310         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3311         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3312         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3313         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3314         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3315         Cvar_RegisterVariable(&r_fog_exp2);
3316         Cvar_RegisterVariable(&r_fog_clear);
3317         Cvar_RegisterVariable(&r_drawfog);
3318         Cvar_RegisterVariable(&r_transparentdepthmasking);
3319         Cvar_RegisterVariable(&r_transparent_sortmindist);
3320         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3321         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3322         Cvar_RegisterVariable(&r_texture_dds_load);
3323         Cvar_RegisterVariable(&r_texture_dds_save);
3324         Cvar_RegisterVariable(&r_usedepthtextures);
3325         Cvar_RegisterVariable(&r_viewfbo);
3326         Cvar_RegisterVariable(&r_rendertarget_debug);
3327         Cvar_RegisterVariable(&r_viewscale);
3328         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3329         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3330         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3331         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3332         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3333         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3334         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3335         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3336         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3337         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3338         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3339         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3340         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3341         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3342         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3343         Cvar_RegisterVariable(&r_glsl_postprocess);
3344         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3345         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3346         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3347         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3348         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3349         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3350         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3351         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3352         Cvar_RegisterVariable(&r_celshading);
3353         Cvar_RegisterVariable(&r_celoutlines);
3354         Cvar_RegisterVariable(&r_fxaa);
3355
3356         Cvar_RegisterVariable(&r_water);
3357         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3358         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3359         Cvar_RegisterVariable(&r_water_clippingplanebias);
3360         Cvar_RegisterVariable(&r_water_refractdistort);
3361         Cvar_RegisterVariable(&r_water_reflectdistort);
3362         Cvar_RegisterVariable(&r_water_scissormode);
3363         Cvar_RegisterVariable(&r_water_lowquality);
3364         Cvar_RegisterVariable(&r_water_hideplayer);
3365
3366         Cvar_RegisterVariable(&r_lerpsprites);
3367         Cvar_RegisterVariable(&r_lerpmodels);
3368         Cvar_RegisterVariable(&r_nolerp_list);
3369         Cvar_RegisterVariable(&r_lerplightstyles);
3370         Cvar_RegisterVariable(&r_waterscroll);
3371         Cvar_RegisterVariable(&r_bloom);
3372         Cvar_RegisterVariable(&r_colorfringe);
3373         Cvar_RegisterVariable(&r_bloom_colorscale);
3374         Cvar_RegisterVariable(&r_bloom_brighten);
3375         Cvar_RegisterVariable(&r_bloom_blur);
3376         Cvar_RegisterVariable(&r_bloom_resolution);
3377         Cvar_RegisterVariable(&r_bloom_colorexponent);
3378         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3379         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3380         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3381         Cvar_RegisterVariable(&r_hdr_glowintensity);
3382         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3383         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3384         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3385         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3386         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3387         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3388         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3389         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3390         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3391         Cvar_RegisterVariable(&developer_texturelogging);
3392         Cvar_RegisterVariable(&gl_lightmaps);
3393         Cvar_RegisterVariable(&r_test);
3394         Cvar_RegisterVariable(&r_batch_multidraw);
3395         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3396         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3397         Cvar_RegisterVariable(&r_glsl_skeletal);
3398         Cvar_RegisterVariable(&r_glsl_saturation);
3399         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3400         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3401         Cvar_RegisterVariable(&r_framedatasize);
3402         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3403                 Cvar_RegisterVariable(&r_buffermegs[i]);
3404         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3405         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3406         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3407         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3408         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3409                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3410 #ifdef DP_MOBILETOUCH
3411         // GLES devices have terrible depth precision in general, so...
3412         Cvar_SetValueQuick(&r_nearclip, 4);
3413         Cvar_SetValueQuick(&r_farclip_base, 4096);
3414         Cvar_SetValueQuick(&r_farclip_world, 0);
3415         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3416 #endif
3417         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3418 }
3419
3420 void Render_Init(void)
3421 {
3422         gl_backend_init();
3423         R_Textures_Init();
3424         GL_Main_Init();
3425         Font_Init();
3426         GL_Draw_Init();
3427         R_Shadow_Init();
3428         R_Sky_Init();
3429         GL_Surf_Init();
3430         Sbar_Init();
3431         R_Particles_Init();
3432         R_Explosion_Init();
3433         R_LightningBeams_Init();
3434         CL_MeshEntities_Init();
3435         Mod_RenderInit();
3436 }
3437
3438 static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits)
3439 {
3440         out[0] = ((signbits & 1) ? mins : maxs)[0];
3441         out[1] = ((signbits & 2) ? mins : maxs)[1];
3442         out[2] = ((signbits & 4) ? mins : maxs)[2];
3443 }
3444
3445 static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore)
3446 {
3447         int i;
3448         const mplane_t *p;
3449         vec3_t corner;
3450         if (r_trippy.integer)
3451                 return false;
3452         for (i = 0;i < numplanes;i++)
3453         {
3454                 if(i == ignore)
3455                         continue;
3456                 p = planes + i;
3457                 R_GetCornerOfBox(corner, mins, maxs, p->signbits);
3458                 if (DotProduct(p->normal, corner) < p->dist)
3459                         return true;
3460         }
3461         return false;
3462 }
3463
3464 qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs)
3465 {
3466         // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
3467         return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4);
3468 }
3469
3470 qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3471 {
3472         // nothing to ignore
3473         return _R_CullBox(mins, maxs, numplanes, planes, -1);
3474 }
3475
3476 //==================================================================================
3477
3478 // LadyHavoc: this stores temporary data used within the same frame
3479
3480 typedef struct r_framedata_mem_s
3481 {
3482         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3483         size_t size; // how much usable space
3484         size_t current; // how much space in use
3485         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3486         size_t wantedsize; // how much space was allocated
3487         unsigned char *data; // start of real data (16byte aligned)
3488 }
3489 r_framedata_mem_t;
3490
3491 static r_framedata_mem_t *r_framedata_mem;
3492
3493 void R_FrameData_Reset(void)
3494 {
3495         while (r_framedata_mem)
3496         {
3497                 r_framedata_mem_t *next = r_framedata_mem->purge;
3498                 Mem_Free(r_framedata_mem);
3499                 r_framedata_mem = next;
3500         }
3501 }
3502
3503 static void R_FrameData_Resize(qbool mustgrow)
3504 {
3505         size_t wantedsize;
3506         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3507         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3508         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3509         {
3510                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3511                 newmem->wantedsize = wantedsize;
3512                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3513                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3514                 newmem->current = 0;
3515                 newmem->mark = 0;
3516                 newmem->purge = r_framedata_mem;
3517                 r_framedata_mem = newmem;
3518         }
3519 }
3520
3521 void R_FrameData_NewFrame(void)
3522 {
3523         R_FrameData_Resize(false);
3524         if (!r_framedata_mem)
3525                 return;
3526         // if we ran out of space on the last frame, free the old memory now
3527         while (r_framedata_mem->purge)
3528         {
3529                 // repeatedly remove the second item in the list, leaving only head
3530                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3531                 Mem_Free(r_framedata_mem->purge);
3532                 r_framedata_mem->purge = next;
3533         }
3534         // reset the current mem pointer
3535         r_framedata_mem->current = 0;
3536         r_framedata_mem->mark = 0;
3537 }
3538
3539 void *R_FrameData_Alloc(size_t size)
3540 {
3541         void *data;
3542         float newvalue;
3543
3544         // align to 16 byte boundary - the data pointer is already aligned, so we
3545         // only need to ensure the size of every allocation is also aligned
3546         size = (size + 15) & ~15;
3547
3548         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3549         {
3550                 // emergency - we ran out of space, allocate more memory
3551                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3552                 newvalue = r_framedatasize.value * 2.0f;
3553                 // 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
3554                 if (sizeof(size_t) >= 8)
3555                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3556                 else
3557                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3558                 // this might not be a growing it, but we'll allocate another buffer every time
3559                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3560                 R_FrameData_Resize(true);
3561         }
3562
3563         data = r_framedata_mem->data + r_framedata_mem->current;
3564         r_framedata_mem->current += size;
3565
3566         // count the usage for stats
3567         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3568         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3569
3570         return (void *)data;
3571 }
3572
3573 void *R_FrameData_Store(size_t size, void *data)
3574 {
3575         void *d = R_FrameData_Alloc(size);
3576         if (d && data)
3577                 memcpy(d, data, size);
3578         return d;
3579 }
3580
3581 void R_FrameData_SetMark(void)
3582 {
3583         if (!r_framedata_mem)
3584                 return;
3585         r_framedata_mem->mark = r_framedata_mem->current;
3586 }
3587
3588 void R_FrameData_ReturnToMark(void)
3589 {
3590         if (!r_framedata_mem)
3591                 return;
3592         r_framedata_mem->current = r_framedata_mem->mark;
3593 }
3594
3595 //==================================================================================
3596
3597 // avoid reusing the same buffer objects on consecutive frames
3598 #define R_BUFFERDATA_CYCLE 3
3599
3600 typedef struct r_bufferdata_buffer_s
3601 {
3602         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3603         size_t size; // how much usable space
3604         size_t current; // how much space in use
3605         r_meshbuffer_t *buffer; // the buffer itself
3606 }
3607 r_bufferdata_buffer_t;
3608
3609 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3610 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3611
3612 /// frees all dynamic buffers
3613 void R_BufferData_Reset(void)
3614 {
3615         int cycle, type;
3616         r_bufferdata_buffer_t **p, *mem;
3617         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3618         {
3619                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3620                 {
3621                         // free all buffers
3622                         p = &r_bufferdata_buffer[cycle][type];
3623                         while (*p)
3624                         {
3625                                 mem = *p;
3626                                 *p = (*p)->purge;
3627                                 if (mem->buffer)
3628                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3629                                 Mem_Free(mem);
3630                         }
3631                 }
3632         }
3633 }
3634
3635 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3636 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3637 {
3638         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3639         size_t size;
3640         float newvalue = r_buffermegs[type].value;
3641
3642         // increase the cvar if we have to (but only if we already have a mem)
3643         if (mustgrow && mem)
3644                 newvalue *= 2.0f;
3645         newvalue = bound(0.25f, newvalue, 256.0f);
3646         while (newvalue * 1024*1024 < minsize)
3647                 newvalue *= 2.0f;
3648
3649         // clamp the cvar to valid range
3650         newvalue = bound(0.25f, newvalue, 256.0f);
3651         if (r_buffermegs[type].value != newvalue)
3652                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3653
3654         // calculate size in bytes
3655         size = (size_t)(newvalue * 1024*1024);
3656         size = bound(131072, size, 256*1024*1024);
3657
3658         // allocate a new buffer if the size is different (purge old one later)
3659         // or if we were told we must grow the buffer
3660         if (!mem || mem->size != size || mustgrow)
3661         {
3662                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3663                 mem->size = size;
3664                 mem->current = 0;
3665                 if (type == R_BUFFERDATA_VERTEX)
3666                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3667                 else if (type == R_BUFFERDATA_INDEX16)
3668                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3669                 else if (type == R_BUFFERDATA_INDEX32)
3670                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3671                 else if (type == R_BUFFERDATA_UNIFORM)
3672                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3673                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3674                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3675         }
3676 }
3677
3678 void R_BufferData_NewFrame(void)
3679 {
3680         int type;
3681         r_bufferdata_buffer_t **p, *mem;
3682         // cycle to the next frame's buffers
3683         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3684         // if we ran out of space on the last time we used these buffers, free the old memory now
3685         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3686         {
3687                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3688                 {
3689                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3690                         // free all but the head buffer, this is how we recycle obsolete
3691                         // buffers after they are no longer in use
3692                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3693                         while (*p)
3694                         {
3695                                 mem = *p;
3696                                 *p = (*p)->purge;
3697                                 if (mem->buffer)
3698                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3699                                 Mem_Free(mem);
3700                         }
3701                         // reset the current offset
3702                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3703                 }
3704         }
3705 }
3706
3707 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3708 {
3709         r_bufferdata_buffer_t *mem;
3710         int offset = 0;
3711         int padsize;
3712
3713         *returnbufferoffset = 0;
3714
3715         // align size to a byte boundary appropriate for the buffer type, this
3716         // makes all allocations have aligned start offsets
3717         if (type == R_BUFFERDATA_UNIFORM)
3718                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3719         else
3720                 padsize = (datasize + 15) & ~15;
3721
3722         // if we ran out of space in this buffer we must allocate a new one
3723         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)
3724                 R_BufferData_Resize(type, true, padsize);
3725
3726         // if the resize did not give us enough memory, fail
3727         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)
3728                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3729
3730         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3731         offset = (int)mem->current;
3732         mem->current += padsize;
3733
3734         // upload the data to the buffer at the chosen offset
3735         if (offset == 0)
3736                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3737         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3738
3739         // count the usage for stats
3740         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3741         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3742
3743         // return the buffer offset
3744         *returnbufferoffset = offset;
3745
3746         return mem->buffer;
3747 }
3748
3749 //==================================================================================
3750
3751 // LadyHavoc: animcache originally written by Echon, rewritten since then
3752
3753 /**
3754  * Animation cache prevents re-generating mesh data for an animated model
3755  * multiple times in one frame for lighting, shadowing, reflections, etc.
3756  */
3757
3758 void R_AnimCache_Free(void)
3759 {
3760 }
3761
3762 void R_AnimCache_ClearCache(void)
3763 {
3764         int i;
3765         entity_render_t *ent;
3766
3767         for (i = 0;i < r_refdef.scene.numentities;i++)
3768         {
3769                 ent = r_refdef.scene.entities[i];
3770                 ent->animcache_vertex3f = NULL;
3771                 ent->animcache_vertex3f_vertexbuffer = NULL;
3772                 ent->animcache_vertex3f_bufferoffset = 0;
3773                 ent->animcache_normal3f = NULL;
3774                 ent->animcache_normal3f_vertexbuffer = NULL;
3775                 ent->animcache_normal3f_bufferoffset = 0;
3776                 ent->animcache_svector3f = NULL;
3777                 ent->animcache_svector3f_vertexbuffer = NULL;
3778                 ent->animcache_svector3f_bufferoffset = 0;
3779                 ent->animcache_tvector3f = NULL;
3780                 ent->animcache_tvector3f_vertexbuffer = NULL;
3781                 ent->animcache_tvector3f_bufferoffset = 0;
3782                 ent->animcache_skeletaltransform3x4 = NULL;
3783                 ent->animcache_skeletaltransform3x4buffer = NULL;
3784                 ent->animcache_skeletaltransform3x4offset = 0;
3785                 ent->animcache_skeletaltransform3x4size = 0;
3786         }
3787 }
3788
3789 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3790 {
3791         model_t *model = ent->model;
3792         int numvertices;
3793
3794         // see if this ent is worth caching
3795         if (!model || !model->Draw || !model->AnimateVertices)
3796                 return false;
3797         // nothing to cache if it contains no animations and has no skeleton
3798         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3799                 return false;
3800         // see if it is already cached for gpuskeletal
3801         if (ent->animcache_skeletaltransform3x4)
3802                 return false;
3803         // see if it is already cached as a mesh
3804         if (ent->animcache_vertex3f)
3805         {
3806                 // check if we need to add normals or tangents
3807                 if (ent->animcache_normal3f)
3808                         wantnormals = false;
3809                 if (ent->animcache_svector3f)
3810                         wanttangents = false;
3811                 if (!wantnormals && !wanttangents)
3812                         return false;
3813         }
3814
3815         // check which kind of cache we need to generate
3816         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3817         {
3818                 // cache the skeleton so the vertex shader can use it
3819                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3820                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3821                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3822                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3823                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4);
3824                 // note: this can fail if the buffer is at the grow limit
3825                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3826                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3827         }
3828         else if (ent->animcache_vertex3f)
3829         {
3830                 // mesh was already cached but we may need to add normals/tangents
3831                 // (this only happens with multiple views, reflections, cameras, etc)
3832                 if (wantnormals || wanttangents)
3833                 {
3834                         numvertices = model->surfmesh.num_vertices;
3835                         if (wantnormals)
3836                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3837                         if (wanttangents)
3838                         {
3839                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3840                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3841                         }
3842                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3843                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3844                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3845                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3846                 }
3847         }
3848         else
3849         {
3850                 // generate mesh cache
3851                 numvertices = model->surfmesh.num_vertices;
3852                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3853                 if (wantnormals)
3854                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3855                 if (wanttangents)
3856                 {
3857                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3858                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3859                 }
3860                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3861                 if (wantnormals || wanttangents)
3862                 {
3863                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3864                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3865                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3866                 }
3867                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3868                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3869                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3870         }
3871         return true;
3872 }
3873
3874 void R_AnimCache_CacheVisibleEntities(void)
3875 {
3876         int i;
3877
3878         // TODO: thread this
3879         // NOTE: R_PrepareRTLights() also caches entities
3880
3881         for (i = 0;i < r_refdef.scene.numentities;i++)
3882                 if (r_refdef.viewcache.entityvisible[i])
3883                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3884 }
3885
3886 //==================================================================================
3887
3888 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)
3889 {
3890         long unsigned int i;
3891         int j;
3892         vec3_t eyemins, eyemaxs;
3893         vec3_t boxmins, boxmaxs;
3894         vec3_t padmins, padmaxs;
3895         vec3_t start;
3896         vec3_t end;
3897         model_t *model = r_refdef.scene.worldmodel;
3898         static vec3_t positions[] = {
3899                 { 0.5f, 0.5f, 0.5f },
3900                 { 0.0f, 0.0f, 0.0f },
3901                 { 0.0f, 0.0f, 1.0f },
3902                 { 0.0f, 1.0f, 0.0f },
3903                 { 0.0f, 1.0f, 1.0f },
3904                 { 1.0f, 0.0f, 0.0f },
3905                 { 1.0f, 0.0f, 1.0f },
3906                 { 1.0f, 1.0f, 0.0f },
3907                 { 1.0f, 1.0f, 1.0f },
3908         };
3909
3910         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3911         if (numsamples < 0)
3912                 return true;
3913
3914         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3915         if (!r_refdef.view.usevieworiginculling)
3916                 return true;
3917
3918         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3919                 return true;
3920
3921         // expand the eye box a little
3922         eyemins[0] = eye[0] - eyejitter;
3923         eyemaxs[0] = eye[0] + eyejitter;
3924         eyemins[1] = eye[1] - eyejitter;
3925         eyemaxs[1] = eye[1] + eyejitter;
3926         eyemins[2] = eye[2] - eyejitter;
3927         eyemaxs[2] = eye[2] + eyejitter;
3928         // expand the box a little
3929         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3930         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3931         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3932         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3933         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3934         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3935         // make an even larger box for the acceptable area
3936         padmins[0] = boxmins[0] - pad;
3937         padmaxs[0] = boxmaxs[0] + pad;
3938         padmins[1] = boxmins[1] - pad;
3939         padmaxs[1] = boxmaxs[1] + pad;
3940         padmins[2] = boxmins[2] - pad;
3941         padmaxs[2] = boxmaxs[2] + pad;
3942
3943         // return true if eye overlaps enlarged box
3944         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3945                 return true;
3946
3947         VectorCopy(eye, start);
3948         // try specific positions in the box first - note that these can be cached
3949         if (r_cullentities_trace_entityocclusion.integer)
3950         {
3951                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3952                 {
3953                         trace_t trace;
3954                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3955                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3956                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3957                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3958                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3959                         // not picky - if the trace ended anywhere in the box we're good
3960                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3961                                 return true;
3962                 }
3963         }
3964         else
3965         {
3966                 // try center
3967                 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
3968                 if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3969                         return true;
3970         }
3971
3972         // try various random positions
3973         for (j = 0; j < numsamples; j++)
3974         {
3975                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3976                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3977                 if (r_cullentities_trace_entityocclusion.integer)
3978                 {
3979                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3980                         // not picky - if the trace ended anywhere in the box we're good
3981                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3982                                 return true;
3983                 }
3984                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3985                         return true;
3986         }
3987
3988         return false;
3989 }
3990
3991
3992 static void R_View_UpdateEntityVisible (void)
3993 {
3994         int i;
3995         int renderimask;
3996         int samples;
3997         entity_render_t *ent;
3998
3999         if (r_refdef.envmap || r_fb.water.hideplayer)
4000                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4001         else if (chase_active.integer || r_fb.water.renderingscene)
4002                 renderimask = RENDER_VIEWMODEL;
4003         else
4004                 renderimask = RENDER_EXTERIORMODEL;
4005         if (!r_drawviewmodel.integer)
4006                 renderimask |= RENDER_VIEWMODEL;
4007         if (!r_drawexteriormodel.integer)
4008                 renderimask |= RENDER_EXTERIORMODEL;
4009         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4010         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4011         {
4012                 // worldmodel can check visibility
4013                 for (i = 0;i < r_refdef.scene.numentities;i++)
4014                 {
4015                         ent = r_refdef.scene.entities[i];
4016                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4017                         {
4018                                 r_refdef.viewcache.entityvisible[i] = false;
4019                                 continue;
4020                         }
4021                         if (!(ent->flags & renderimask))
4022                         if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4023                         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))
4024                                 r_refdef.viewcache.entityvisible[i] = true;
4025                 }
4026         }
4027         else
4028         {
4029                 // no worldmodel or it can't check visibility
4030                 for (i = 0;i < r_refdef.scene.numentities;i++)
4031                 {
4032                         ent = r_refdef.scene.entities[i];
4033                         if (!(ent->flags & renderimask))
4034                         if (!R_CullFrustum(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4035                                 r_refdef.viewcache.entityvisible[i] = true;
4036                 }
4037         }
4038         if (r_cullentities_trace.integer)
4039         {
4040                 for (i = 0;i < r_refdef.scene.numentities;i++)
4041                 {
4042                         if (!r_refdef.viewcache.entityvisible[i])
4043                                 continue;
4044                         ent = r_refdef.scene.entities[i];
4045                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4046                         {
4047                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4048                                 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))
4049                                         ent->last_trace_visibility = host.realtime;
4050                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4051                                         r_refdef.viewcache.entityvisible[i] = 0;
4052                         }
4053                 }
4054         }
4055 }
4056
4057 /// only used if skyrendermasked, and normally returns false
4058 static int R_DrawBrushModelsSky (void)
4059 {
4060         int i, sky;
4061         entity_render_t *ent;
4062
4063         sky = false;
4064         for (i = 0;i < r_refdef.scene.numentities;i++)
4065         {
4066                 if (!r_refdef.viewcache.entityvisible[i])
4067                         continue;
4068                 ent = r_refdef.scene.entities[i];
4069                 if (!ent->model || !ent->model->DrawSky)
4070                         continue;
4071                 ent->model->DrawSky(ent);
4072                 sky = true;
4073         }
4074         return sky;
4075 }
4076
4077 static void R_DrawNoModel(entity_render_t *ent);
4078 static void R_DrawModels(void)
4079 {
4080         int i;
4081         entity_render_t *ent;
4082
4083         for (i = 0;i < r_refdef.scene.numentities;i++)
4084         {
4085                 if (!r_refdef.viewcache.entityvisible[i])
4086                         continue;
4087                 ent = r_refdef.scene.entities[i];
4088                 r_refdef.stats[r_stat_entities]++;
4089
4090                 if (ent->model && ent->model->Draw != NULL)
4091                         ent->model->Draw(ent);
4092                 else
4093                         R_DrawNoModel(ent);
4094         }
4095 }
4096
4097 static void R_DrawModelsDepth(void)
4098 {
4099         int i;
4100         entity_render_t *ent;
4101
4102         for (i = 0;i < r_refdef.scene.numentities;i++)
4103         {
4104                 if (!r_refdef.viewcache.entityvisible[i])
4105                         continue;
4106                 ent = r_refdef.scene.entities[i];
4107                 if (ent->model && ent->model->DrawDepth != NULL)
4108                         ent->model->DrawDepth(ent);
4109         }
4110 }
4111
4112 static void R_DrawModelsDebug(void)
4113 {
4114         int i;
4115         entity_render_t *ent;
4116
4117         for (i = 0;i < r_refdef.scene.numentities;i++)
4118         {
4119                 if (!r_refdef.viewcache.entityvisible[i])
4120                         continue;
4121                 ent = r_refdef.scene.entities[i];
4122                 if (ent->model && ent->model->DrawDebug != NULL)
4123                         ent->model->DrawDebug(ent);
4124         }
4125 }
4126
4127 static void R_DrawModelsAddWaterPlanes(void)
4128 {
4129         int i;
4130         entity_render_t *ent;
4131
4132         for (i = 0;i < r_refdef.scene.numentities;i++)
4133         {
4134                 if (!r_refdef.viewcache.entityvisible[i])
4135                         continue;
4136                 ent = r_refdef.scene.entities[i];
4137                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4138                         ent->model->DrawAddWaterPlanes(ent);
4139         }
4140 }
4141
4142 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}};
4143
4144 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4145 {
4146         if (r_hdr_irisadaptation.integer)
4147         {
4148                 vec3_t p;
4149                 vec3_t ambient;
4150                 vec3_t diffuse;
4151                 vec3_t diffusenormal;
4152                 vec3_t forward;
4153                 vec_t brightness = 0.0f;
4154                 vec_t goal;
4155                 vec_t current;
4156                 vec_t d;
4157                 int c;
4158                 VectorCopy(r_refdef.view.forward, forward);
4159                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4160                 {
4161                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4162                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4163                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4164                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4165                         d = DotProduct(forward, diffusenormal);
4166                         brightness += VectorLength(ambient);
4167                         if (d > 0)
4168                                 brightness += d * VectorLength(diffuse);
4169                 }
4170                 brightness *= 1.0f / c;
4171                 brightness += 0.00001f; // make sure it's never zero
4172                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4173                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4174                 current = r_hdr_irisadaptation_value.value;
4175                 if (current < goal)
4176                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4177                 else if (current > goal)
4178                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4179                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4180                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4181         }
4182         else if (r_hdr_irisadaptation_value.value != 1.0f)
4183                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4184 }
4185
4186 extern cvar_t r_lockvisibility;
4187 extern cvar_t r_lockpvs;
4188
4189 static void R_View_SetFrustum(const int *scissor)
4190 {
4191         int i;
4192         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4193         vec3_t forward, left, up, origin, v;
4194         if(r_lockvisibility.integer)
4195                 return;
4196         if(scissor)
4197         {
4198                 // flipped x coordinates (because x points left here)
4199                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4200                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4201                 // non-flipped y coordinates
4202                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4203                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4204         }
4205
4206         // we can't trust r_refdef.view.forward and friends in reflected scenes
4207         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4208
4209 #if 0
4210         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4211         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4212         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4213         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4214         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4215         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4216         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4217         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4218         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4219         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4220         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4221         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4222 #endif
4223
4224 #if 0
4225         zNear = r_refdef.nearclip;
4226         nudge = 1.0 - 1.0 / (1<<23);
4227         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4228         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4229         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4230         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4231         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4232         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4233         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4234         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4235 #endif
4236
4237
4238
4239 #if 0
4240         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4241         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4242         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4243         r_refdef.view.frustum[0].dist = m[15] - m[12];
4244
4245         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4246         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4247         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4248         r_refdef.view.frustum[1].dist = m[15] + m[12];
4249
4250         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4251         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4252         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4253         r_refdef.view.frustum[2].dist = m[15] - m[13];
4254
4255         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4256         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4257         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4258         r_refdef.view.frustum[3].dist = m[15] + m[13];
4259
4260         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4261         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4262         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4263         r_refdef.view.frustum[4].dist = m[15] - m[14];
4264
4265         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4266         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4267         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4268         r_refdef.view.frustum[5].dist = m[15] + m[14];
4269 #endif
4270
4271         if (r_refdef.view.useperspective)
4272         {
4273                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4274                 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]);
4275                 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]);
4276                 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]);
4277                 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]);
4278
4279                 // then the normals from the corners relative to origin
4280                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4281                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4282                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4283                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4284
4285                 // in a NORMAL view, forward cross left == up
4286                 // in a REFLECTED view, forward cross left == down
4287                 // so our cross products above need to be adjusted for a left handed coordinate system
4288                 CrossProduct(forward, left, v);
4289                 if(DotProduct(v, up) < 0)
4290                 {
4291                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4292                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4293                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4294                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4295                 }
4296
4297                 // Leaving those out was a mistake, those were in the old code, and they
4298                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4299                 // I couldn't reproduce it after adding those normalizations. --blub
4300                 VectorNormalize(r_refdef.view.frustum[0].normal);
4301                 VectorNormalize(r_refdef.view.frustum[1].normal);
4302                 VectorNormalize(r_refdef.view.frustum[2].normal);
4303                 VectorNormalize(r_refdef.view.frustum[3].normal);
4304
4305                 // make the corners absolute
4306                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4307                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4308                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4309                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4310
4311                 // one more normal
4312                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4313
4314                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4315                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4316                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4317                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4318                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4319         }
4320         else
4321         {
4322                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4323                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4324                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4325                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4326                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4327                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4328                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4329                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4330                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4331                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4332         }
4333         r_refdef.view.numfrustumplanes = 5;
4334
4335         if (r_refdef.view.useclipplane)
4336         {
4337                 r_refdef.view.numfrustumplanes = 6;
4338                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4339         }
4340
4341         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4342                 PlaneClassify(r_refdef.view.frustum + i);
4343
4344         // LadyHavoc: note to all quake engine coders, Quake had a special case
4345         // for 90 degrees which assumed a square view (wrong), so I removed it,
4346         // Quake2 has it disabled as well.
4347
4348         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4349         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4350         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4351         //PlaneClassify(&frustum[0]);
4352
4353         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4354         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4355         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4356         //PlaneClassify(&frustum[1]);
4357
4358         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4359         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4360         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4361         //PlaneClassify(&frustum[2]);
4362
4363         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4364         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4365         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4366         //PlaneClassify(&frustum[3]);
4367
4368         // nearclip plane
4369         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4370         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4371         //PlaneClassify(&frustum[4]);
4372 }
4373
4374 static void R_View_Update(const int *myscissor)
4375 {
4376         R_Main_ResizeViewCache();
4377         R_View_SetFrustum(myscissor);
4378         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4379         R_View_UpdateEntityVisible();
4380 }
4381
4382 float viewscalefpsadjusted = 1.0f;
4383
4384 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4385 {
4386         const float *customclipplane = NULL;
4387         float plane[4];
4388         int viewy_adjusted;
4389         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4390         {
4391                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4392                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4393                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4394                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4395                         dist = r_refdef.view.clipplane.dist;
4396                 plane[0] = r_refdef.view.clipplane.normal[0];
4397                 plane[1] = r_refdef.view.clipplane.normal[1];
4398                 plane[2] = r_refdef.view.clipplane.normal[2];
4399                 plane[3] = -dist;
4400                 customclipplane = plane;
4401         }
4402
4403         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
4404         // Unless the render target is a FBO...
4405         viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy;
4406
4407         if (!r_refdef.view.useperspective)
4408                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4409         else if (vid.stencil && r_useinfinitefarclip.integer)
4410                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4411         else
4412                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, viewy_adjusted, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4413         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4414         R_SetViewport(&r_refdef.view.viewport);
4415 }
4416
4417 void R_EntityMatrix(const matrix4x4_t *matrix)
4418 {
4419         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4420         {
4421                 gl_modelmatrixchanged = false;
4422                 gl_modelmatrix = *matrix;
4423                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4424                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4425                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4426                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4427                 CHECKGLERROR
4428                 switch(vid.renderpath)
4429                 {
4430                 case RENDERPATH_GL32:
4431                 case RENDERPATH_GLES2:
4432                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4433                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4434                         break;
4435                 }
4436         }
4437 }
4438
4439 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4440 {
4441         r_viewport_t viewport;
4442         int viewy_adjusted;
4443
4444         CHECKGLERROR
4445
4446         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom.
4447         // Unless the render target is a FBO...
4448         viewy_adjusted = viewfbo ? viewy : vid.mode.height - viewheight - viewy;
4449
4450         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, viewy_adjusted, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4451         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4452         R_SetViewport(&viewport);
4453         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4454         GL_Color(1, 1, 1, 1);
4455         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4456         GL_BlendFunc(GL_ONE, GL_ZERO);
4457         GL_ScissorTest(false);
4458         GL_DepthMask(false);
4459         GL_DepthRange(0, 1);
4460         GL_DepthTest(false);
4461         GL_DepthFunc(GL_LEQUAL);
4462         R_EntityMatrix(&identitymatrix);
4463         R_Mesh_ResetTextureState();
4464         GL_PolygonOffset(0, 0);
4465         switch(vid.renderpath)
4466         {
4467         case RENDERPATH_GL32:
4468         case RENDERPATH_GLES2:
4469                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4470                 break;
4471         }
4472         GL_CullFace(GL_NONE);
4473
4474         CHECKGLERROR
4475 }
4476
4477 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4478 {
4479         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4480 }
4481
4482 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4483 {
4484         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4485         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4486         GL_Color(1, 1, 1, 1);
4487         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4488         GL_BlendFunc(GL_ONE, GL_ZERO);
4489         GL_ScissorTest(true);
4490         GL_DepthMask(true);
4491         GL_DepthRange(0, 1);
4492         GL_DepthTest(true);
4493         GL_DepthFunc(GL_LEQUAL);
4494         R_EntityMatrix(&identitymatrix);
4495         R_Mesh_ResetTextureState();
4496         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4497         switch(vid.renderpath)
4498         {
4499         case RENDERPATH_GL32:
4500         case RENDERPATH_GLES2:
4501                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4502                 break;
4503         }
4504         GL_CullFace(r_refdef.view.cullface_back);
4505 }
4506
4507 /*
4508 ================
4509 R_RenderView_UpdateViewVectors
4510 ================
4511 */
4512 void R_RenderView_UpdateViewVectors(void)
4513 {
4514         // break apart the view matrix into vectors for various purposes
4515         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4516         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4517         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4518         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4519         // make an inverted copy of the view matrix for tracking sprites
4520         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4521 }
4522
4523 void R_RenderTarget_FreeUnused(qbool force)
4524 {
4525         unsigned int i, j, end;
4526         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4527         for (i = 0; i < end; i++)
4528         {
4529                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4530                 // free resources for rendertargets that have not been used for a while
4531                 // (note: this check is run after the frame render, so any targets used
4532                 // this frame will not be affected even at low framerates)
4533                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4534                 {
4535                         if (r->fbo)
4536                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4537                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4538                                 if (r->colortexture[j])
4539                                         R_FreeTexture(r->colortexture[j]);
4540                         if (r->depthtexture)
4541                                 R_FreeTexture(r->depthtexture);
4542                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4543                 }
4544         }
4545 }
4546
4547 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4548 {
4549         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4550         x1 = x * iw;
4551         x2 = (x + w) * iw;
4552         y1 = (th - y) * ih;
4553         y2 = (th - y - h) * ih;
4554         texcoord2f[0] = x1;
4555         texcoord2f[2] = x2;
4556         texcoord2f[4] = x2;
4557         texcoord2f[6] = x1;
4558         texcoord2f[1] = y1;
4559         texcoord2f[3] = y1;
4560         texcoord2f[5] = y2;
4561         texcoord2f[7] = y2;
4562 }
4563
4564 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)
4565 {
4566         unsigned int i, j, end;
4567         r_rendertarget_t *r = NULL;
4568         char vabuf[256];
4569         // first try to reuse an existing slot if possible
4570         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4571         for (i = 0; i < end; i++)
4572         {
4573                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4574                 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)
4575                         break;
4576         }
4577         if (i == end)
4578         {
4579                 // no unused exact match found, so we have to make one in the first unused slot
4580                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4581                 r->texturewidth = texturewidth;
4582                 r->textureheight = textureheight;
4583                 r->colortextype[0] = colortextype0;
4584                 r->colortextype[1] = colortextype1;
4585                 r->colortextype[2] = colortextype2;
4586                 r->colortextype[3] = colortextype3;
4587                 r->depthtextype = depthtextype;
4588                 r->depthisrenderbuffer = depthisrenderbuffer;
4589                 for (j = 0; j < 4; j++)
4590                         if (r->colortextype[j])
4591                                 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);
4592                 if (r->depthtextype)
4593                 {
4594                         if (r->depthisrenderbuffer)
4595                                 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);
4596                         else
4597                                 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);
4598                 }
4599                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4600         }
4601         r_refdef.stats[r_stat_rendertargets_used]++;
4602         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4603         r->lastusetime = host.realtime;
4604         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4605         return r;
4606 }
4607
4608 static void R_Water_StartFrame(int viewwidth, int viewheight)
4609 {
4610         int waterwidth, waterheight;
4611
4612         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4613                 return;
4614
4615         // set waterwidth and waterheight to the water resolution that will be
4616         // used (often less than the screen resolution for faster rendering)
4617         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4618         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4619
4620         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4621                 waterwidth = waterheight = 0;
4622
4623         // set up variables that will be used in shader setup
4624         r_fb.water.waterwidth = waterwidth;
4625         r_fb.water.waterheight = waterheight;
4626         r_fb.water.texturewidth = waterwidth;
4627         r_fb.water.textureheight = waterheight;
4628         r_fb.water.camerawidth = waterwidth;
4629         r_fb.water.cameraheight = waterheight;
4630         r_fb.water.screenscale[0] = 0.5f;
4631         r_fb.water.screenscale[1] = 0.5f;
4632         r_fb.water.screencenter[0] = 0.5f;
4633         r_fb.water.screencenter[1] = 0.5f;
4634         r_fb.water.enabled = waterwidth != 0;
4635
4636         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4637         r_fb.water.numwaterplanes = 0;
4638 }
4639
4640 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4641 {
4642         int planeindex, bestplaneindex, vertexindex;
4643         vec3_t mins, maxs, normal, center, v, n;
4644         vec_t planescore, bestplanescore;
4645         mplane_t plane;
4646         r_waterstate_waterplane_t *p;
4647         texture_t *t = R_GetCurrentTexture(surface->texture);
4648
4649         rsurface.texture = t;
4650         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4651         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4652         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4653                 return;
4654         // average the vertex normals, find the surface bounds (after deformvertexes)
4655         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4656         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4657         VectorCopy(n, normal);
4658         VectorCopy(v, mins);
4659         VectorCopy(v, maxs);
4660         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4661         {
4662                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4663                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4664                 VectorAdd(normal, n, normal);
4665                 mins[0] = min(mins[0], v[0]);
4666                 mins[1] = min(mins[1], v[1]);
4667                 mins[2] = min(mins[2], v[2]);
4668                 maxs[0] = max(maxs[0], v[0]);
4669                 maxs[1] = max(maxs[1], v[1]);
4670                 maxs[2] = max(maxs[2], v[2]);
4671         }
4672         VectorNormalize(normal);
4673         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4674
4675         VectorCopy(normal, plane.normal);
4676         VectorNormalize(plane.normal);
4677         plane.dist = DotProduct(center, plane.normal);
4678         PlaneClassify(&plane);
4679         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4680         {
4681                 // skip backfaces (except if nocullface is set)
4682 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4683 //                      return;
4684                 VectorNegate(plane.normal, plane.normal);
4685                 plane.dist *= -1;
4686                 PlaneClassify(&plane);
4687         }
4688
4689
4690         // find a matching plane if there is one
4691         bestplaneindex = -1;
4692         bestplanescore = 1048576.0f;
4693         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4694         {
4695                 if(p->camera_entity == t->camera_entity)
4696                 {
4697                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4698                         if (bestplaneindex < 0 || bestplanescore > planescore)
4699                         {
4700                                 bestplaneindex = planeindex;
4701                                 bestplanescore = planescore;
4702                         }
4703                 }
4704         }
4705         planeindex = bestplaneindex;
4706
4707         // if this surface does not fit any known plane rendered this frame, add one
4708         if (planeindex < 0 || bestplanescore > 0.001f)
4709         {
4710                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4711                 {
4712                         // store the new plane
4713                         planeindex = r_fb.water.numwaterplanes++;
4714                         p = r_fb.water.waterplanes + planeindex;
4715                         p->plane = plane;
4716                         // clear materialflags and pvs
4717                         p->materialflags = 0;
4718                         p->pvsvalid = false;
4719                         p->camera_entity = t->camera_entity;
4720                         VectorCopy(mins, p->mins);
4721                         VectorCopy(maxs, p->maxs);
4722                 }
4723                 else
4724                 {
4725                         // We're totally screwed.
4726                         return;
4727                 }
4728         }
4729         else
4730         {
4731                 // merge mins/maxs when we're adding this surface to the plane
4732                 p = r_fb.water.waterplanes + planeindex;
4733                 p->mins[0] = min(p->mins[0], mins[0]);
4734                 p->mins[1] = min(p->mins[1], mins[1]);
4735                 p->mins[2] = min(p->mins[2], mins[2]);
4736                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4737                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4738                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4739         }
4740         // merge this surface's materialflags into the waterplane
4741         p->materialflags |= t->currentmaterialflags;
4742         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4743         {
4744                 // merge this surface's PVS into the waterplane
4745                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4746                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4747                 {
4748                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, &p->pvsbits, r_main_mempool, p->pvsvalid);
4749                         p->pvsvalid = true;
4750                 }
4751         }
4752 }
4753
4754 extern cvar_t r_drawparticles;
4755 extern cvar_t r_drawdecals;
4756
4757 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4758 {
4759         int myscissor[4];
4760         r_refdef_view_t originalview;
4761         r_refdef_view_t myview;
4762         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;
4763         r_waterstate_waterplane_t *p;
4764         vec3_t visorigin;
4765         r_rendertarget_t *rt;
4766
4767         originalview = r_refdef.view;
4768
4769         // lowquality hack, temporarily shut down some cvars and restore afterwards
4770         qualityreduction = r_water_lowquality.integer;
4771         if (qualityreduction > 0)
4772         {
4773                 if (qualityreduction >= 1)
4774                 {
4775                         old_r_shadows = r_shadows.integer;
4776                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4777                         old_r_dlight = r_shadow_realtime_dlight.integer;
4778                         Cvar_SetValueQuick(&r_shadows, 0);
4779                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4780                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4781                 }
4782                 if (qualityreduction >= 2)
4783                 {
4784                         old_r_dynamic = r_dynamic.integer;
4785                         old_r_particles = r_drawparticles.integer;
4786                         old_r_decals = r_drawdecals.integer;
4787                         Cvar_SetValueQuick(&r_dynamic, 0);
4788                         Cvar_SetValueQuick(&r_drawparticles, 0);
4789                         Cvar_SetValueQuick(&r_drawdecals, 0);
4790                 }
4791         }
4792
4793         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4794         {
4795                 p->rt_reflection = NULL;
4796                 p->rt_refraction = NULL;
4797                 p->rt_camera = NULL;
4798         }
4799
4800         // render views
4801         r_refdef.view = originalview;
4802         r_refdef.view.showdebug = false;
4803         r_refdef.view.width = r_fb.water.waterwidth;
4804         r_refdef.view.height = r_fb.water.waterheight;
4805         r_refdef.view.useclipplane = true;
4806         myview = r_refdef.view;
4807         r_fb.water.renderingscene = true;
4808         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4809         {
4810                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4811                         continue;
4812
4813                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4814                 {
4815                         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);
4816                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4817                                 goto error;
4818                         r_refdef.view = myview;
4819                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4820                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4821                         if(r_water_scissormode.integer)
4822                         {
4823                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4824                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4825                                 {
4826                                         p->rt_reflection = NULL;
4827                                         p->rt_refraction = NULL;
4828                                         p->rt_camera = NULL;
4829                                         continue;
4830                                 }
4831                         }
4832
4833                         r_refdef.view.clipplane = p->plane;
4834                         // reflected view origin may be in solid, so don't cull with it
4835                         r_refdef.view.usevieworiginculling = false;
4836                         // reverse the cullface settings for this render
4837                         r_refdef.view.cullface_front = GL_FRONT;
4838                         r_refdef.view.cullface_back = GL_BACK;
4839                         // combined pvs (based on what can be seen from each surface center)
4840                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4841                         {
4842                                 r_refdef.view.usecustompvs = true;
4843                                 if (p->pvsvalid)
4844                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4845                                 else
4846                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4847                         }
4848
4849                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4850                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4851                         GL_ScissorTest(false);
4852                         R_ClearScreen(r_refdef.fogenabled);
4853                         GL_ScissorTest(true);
4854                         R_View_Update(r_water_scissormode.integer & 2 ? myscissor : NULL);
4855                         R_AnimCache_CacheVisibleEntities();
4856                         if(r_water_scissormode.integer & 1)
4857                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4858                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4859
4860                         r_fb.water.hideplayer = false;
4861                         p->rt_reflection = rt;
4862                 }
4863
4864                 // render the normal view scene and copy into texture
4865                 // (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)
4866                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4867                 {
4868                         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);
4869                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4870                                 goto error;
4871                         r_refdef.view = myview;
4872                         if(r_water_scissormode.integer)
4873                         {
4874                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4875                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4876                                 {
4877                                         p->rt_reflection = NULL;
4878                                         p->rt_refraction = NULL;
4879                                         p->rt_camera = NULL;
4880                                         continue;
4881                                 }
4882                         }
4883
4884                         // combined pvs (based on what can be seen from each surface center)
4885                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4886                         {
4887                                 r_refdef.view.usecustompvs = true;
4888                                 if (p->pvsvalid)
4889                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4890                                 else
4891                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4892                         }
4893
4894                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4895
4896                         r_refdef.view.clipplane = p->plane;
4897                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4898                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4899
4900                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4901                         {
4902                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4903                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4904                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4905                                 R_RenderView_UpdateViewVectors();
4906                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4907                                 {
4908                                         r_refdef.view.usecustompvs = true;
4909                                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, &r_refdef.viewcache.world_pvsbits, r_main_mempool, false);
4910                                 }
4911                         }
4912
4913                         PlaneClassify(&r_refdef.view.clipplane);
4914
4915                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4916                         GL_ScissorTest(false);
4917                         R_ClearScreen(r_refdef.fogenabled);
4918                         GL_ScissorTest(true);
4919                         R_View_Update(r_water_scissormode.integer & 2 ? myscissor : NULL);
4920                         R_AnimCache_CacheVisibleEntities();
4921                         if(r_water_scissormode.integer & 1)
4922                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4923                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4924
4925                         r_fb.water.hideplayer = false;
4926                         p->rt_refraction = rt;
4927                 }
4928                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4929                 {
4930                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4931                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4932                                 goto error;
4933                         r_refdef.view = myview;
4934
4935                         r_refdef.view.clipplane = p->plane;
4936                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4937                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4938
4939                         r_refdef.view.width = r_fb.water.camerawidth;
4940                         r_refdef.view.height = r_fb.water.cameraheight;
4941                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4942                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4943                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4944                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4945
4946                         if(p->camera_entity)
4947                         {
4948                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4949                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4950                         }
4951
4952                         // note: all of the view is used for displaying... so
4953                         // there is no use in scissoring
4954
4955                         // reverse the cullface settings for this render
4956                         r_refdef.view.cullface_front = GL_FRONT;
4957                         r_refdef.view.cullface_back = GL_BACK;
4958                         // also reverse the view matrix
4959                         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
4960                         R_RenderView_UpdateViewVectors();
4961                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4962                         {
4963                                 r_refdef.view.usecustompvs = true;
4964                                 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, &r_refdef.viewcache.world_pvsbits, r_main_mempool, false);
4965                         }
4966
4967                         // camera needs no clipplane
4968                         r_refdef.view.useclipplane = false;
4969                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4970                         r_refdef.view.usevieworiginculling = false;
4971
4972                         PlaneClassify(&r_refdef.view.clipplane);
4973
4974                         r_fb.water.hideplayer = false;
4975
4976                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4977                         GL_ScissorTest(false);
4978                         R_ClearScreen(r_refdef.fogenabled);
4979                         GL_ScissorTest(true);
4980                         R_View_Update(NULL);
4981                         R_AnimCache_CacheVisibleEntities();
4982                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4983
4984                         r_fb.water.hideplayer = false;
4985                         p->rt_camera = rt;
4986                 }
4987
4988         }
4989         r_fb.water.renderingscene = false;
4990         r_refdef.view = originalview;
4991         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
4992         R_View_Update(NULL);
4993         R_AnimCache_CacheVisibleEntities();
4994         goto finish;
4995 error:
4996         r_refdef.view = originalview;
4997         r_fb.water.renderingscene = false;
4998         Cvar_SetValueQuick(&r_water, 0);
4999         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5000 finish:
5001         // lowquality hack, restore cvars
5002         if (qualityreduction > 0)
5003         {
5004                 if (qualityreduction >= 1)
5005                 {
5006                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5007                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5008                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5009                 }
5010                 if (qualityreduction >= 2)
5011                 {
5012                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5013                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5014                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5015                 }
5016         }
5017 }
5018
5019 static void R_Bloom_StartFrame(void)
5020 {
5021         int screentexturewidth, screentextureheight;
5022         textype_t textype = TEXTYPE_COLORBUFFER;
5023         double scale;
5024
5025         // clear the pointers to rendertargets from last frame as they're stale
5026         r_fb.rt_screen = NULL;
5027         r_fb.rt_bloom = NULL;
5028
5029         switch (vid.renderpath)
5030         {
5031         case RENDERPATH_GL32:
5032                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5033                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5034                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5035                 break;
5036         case RENDERPATH_GLES2:
5037                 r_fb.usedepthtextures = false;
5038                 break;
5039         }
5040
5041         if (r_viewscale_fpsscaling.integer)
5042         {
5043                 double actualframetime;
5044                 double targetframetime;
5045                 double adjust;
5046                 actualframetime = r_refdef.lastdrawscreentime;
5047                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5048                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5049                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5050                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5051                 {
5052                         if (adjust > 0)
5053                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5054                         else
5055                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5056                 }
5057                 viewscalefpsadjusted += adjust;
5058                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5059         }
5060         else
5061                 viewscalefpsadjusted = 1.0f;
5062
5063         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5064         if (vid.mode.samples)
5065                 scale *= sqrt(vid.mode.samples); // supersampling
5066         scale = bound(0.03125f, scale, 4.0f);
5067         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5068         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5069         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5070         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5071
5072         // set bloomwidth and bloomheight to the bloom resolution that will be
5073         // used (often less than the screen resolution for faster rendering)
5074         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5075         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5076         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5077         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5078         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5079
5080         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))
5081         {
5082                 Cvar_SetValueQuick(&r_bloom, 0);
5083                 Cvar_SetValueQuick(&r_motionblur, 0);
5084                 Cvar_SetValueQuick(&r_damageblur, 0);
5085         }
5086         if (!r_bloom.integer)
5087                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5088
5089         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5090         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5091         {
5092                 if (r_fb.ghosttexture)
5093                         R_FreeTexture(r_fb.ghosttexture);
5094                 r_fb.ghosttexture = NULL;
5095
5096                 r_fb.screentexturewidth = screentexturewidth;
5097                 r_fb.screentextureheight = screentextureheight;
5098                 r_fb.textype = textype;
5099
5100                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5101                 {
5102                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5103                                 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);
5104                         r_fb.ghosttexture_valid = false;
5105                 }
5106         }
5107
5108         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5109
5110         r_refdef.view.clear = true;
5111 }
5112
5113 static void R_Bloom_MakeTexture(void)
5114 {
5115         int x, range, dir;
5116         float xoffset, yoffset, r, brighten;
5117         float colorscale = r_bloom_colorscale.value;
5118         r_viewport_t bloomviewport;
5119         r_rendertarget_t *prev, *cur;
5120         textype_t textype = r_fb.rt_screen->colortextype[0];
5121
5122         r_refdef.stats[r_stat_bloom]++;
5123
5124         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5125
5126         // scale down screen texture to the bloom texture size
5127         CHECKGLERROR
5128         prev = r_fb.rt_screen;
5129         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5130         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5131         R_SetViewport(&bloomviewport);
5132         GL_CullFace(GL_NONE);
5133         GL_DepthTest(false);
5134         GL_BlendFunc(GL_ONE, GL_ZERO);
5135         GL_Color(colorscale, colorscale, colorscale, 1);
5136         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5137         // TODO: do boxfilter scale-down in shader?
5138         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5139         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5140         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5141         // we now have a properly scaled bloom image
5142
5143         // multiply bloom image by itself as many times as desired to darken it
5144         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5145         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5146         {
5147                 prev = cur;
5148                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5149                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5150                 x *= 2;
5151                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5152                 if(x <= 2)
5153                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5154                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5155                 GL_Color(1,1,1,1); // no fix factor supported here
5156                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5157                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5158                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5159                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5160         }
5161         CHECKGLERROR
5162
5163         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5164         brighten = r_bloom_brighten.value;
5165         brighten = sqrt(brighten);
5166         if(range >= 1)
5167                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5168
5169         for (dir = 0;dir < 2;dir++)
5170         {
5171                 prev = cur;
5172                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5173                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5174                 // blend on at multiple vertical offsets to achieve a vertical blur
5175                 // TODO: do offset blends using GLSL
5176                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5177                 CHECKGLERROR
5178                 GL_BlendFunc(GL_ONE, GL_ZERO);
5179                 CHECKGLERROR
5180                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5181                 CHECKGLERROR
5182                 for (x = -range;x <= range;x++)
5183                 {
5184                         if (!dir){xoffset = 0;yoffset = x;}
5185                         else {xoffset = x;yoffset = 0;}
5186                         xoffset /= (float)prev->texturewidth;
5187                         yoffset /= (float)prev->textureheight;
5188                         // compute a texcoord array with the specified x and y offset
5189                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5190                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5191                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5192                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5193                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5194                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5195                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5196                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5197                         // this r value looks like a 'dot' particle, fading sharply to
5198                         // black at the edges
5199                         // (probably not realistic but looks good enough)
5200                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5201                         //r = brighten/(range*2+1);
5202                         r = brighten / (range * 2 + 1);
5203                         if(range >= 1)
5204                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5205                         if (r <= 0)
5206                                 continue;
5207                         CHECKGLERROR
5208                         GL_Color(r, r, r, 1);
5209                         CHECKGLERROR
5210                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5211                         CHECKGLERROR
5212                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5213                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5214                         CHECKGLERROR
5215                         GL_BlendFunc(GL_ONE, GL_ONE);
5216                         CHECKGLERROR
5217                 }
5218         }
5219
5220         // now we have the bloom image, so keep track of it
5221         r_fb.rt_bloom = cur;
5222 }
5223
5224 static qbool R_BlendView_IsTrivial(int viewwidth, int viewheight, int width, int height)
5225 {
5226         // Scaling requested?
5227         if (viewwidth != width || viewheight != height)
5228                 return false;
5229         // Higher bit depth or explicit FBO requested?
5230         if (r_viewfbo.integer)
5231                 return false;
5232         // Non-trivial postprocessing shader permutation?
5233         if (r_fb.bloomwidth
5234         || r_refdef.viewblend[3] > 0
5235         || !vid_gammatables_trivial
5236         || r_glsl_postprocess.integer
5237         || ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1)))
5238                 return false;
5239         // Other reasons for a non-trivial default postprocessing shader?
5240         // (See R_CompileShader_CheckStaticParms but only those relevant for MODE_POSTPROCESS in shader_glsl.h)
5241         // Skip: if (r_glsl_saturation_redcompensate.integer) (already covered by saturation above).
5242         // Skip: if (r_glsl_postprocess.integer) (already covered by r_glsl_postprocess above).
5243         // Skip: if (r_glsl_postprocess_uservec1_enable.integer) (already covered by r_glsl_postprocessing above).
5244         if (r_fxaa.integer)
5245                 return false;
5246         if (r_colorfringe.value)
5247                 return false;
5248         return true;
5249 }
5250
5251 static void R_MotionBlurView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5252 {
5253         R_EntityMatrix(&identitymatrix);
5254
5255         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || (r_damageblur.value > 0 && cl.cshifts[CSHIFT_DAMAGE].percent != 0)) && r_fb.ghosttexture)
5256         {
5257                 // declare variables
5258                 float blur_factor, blur_mouseaccel, blur_velocity;
5259                 static float blur_average;
5260                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5261
5262                 // set a goal for the factoring
5263                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value)
5264                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5265                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value)
5266                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5267                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value)
5268                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5269
5270                 // from the goal, pick an averaged value between goal and last value
5271                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5272                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5273
5274                 // enforce minimum amount of blur
5275                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5276
5277                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5278
5279                 // calculate values into a standard alpha
5280                 cl.motionbluralpha = 1 - exp(-
5281                                 (
5282                                         (r_motionblur.value * blur_factor / 80)
5283                                         +
5284                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5285                                 )
5286                                 /
5287                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5288                                 );
5289
5290                 // randomization for the blur value to combat persistent ghosting
5291                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5292                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5293
5294                 // apply the blur on top of the current view
5295                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5296                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5297                 {
5298                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5299                         GL_Color(1, 1, 1, cl.motionbluralpha);
5300                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5301                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5302                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5303                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5304                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5305                 }
5306
5307                 // updates old view angles for next pass
5308                 VectorCopy(cl.viewangles, blur_oldangles);
5309
5310                 // copy view into the ghost texture
5311                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5312                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5313                 r_fb.ghosttexture_valid = true;
5314         }
5315 }
5316
5317 static void R_BlendView(rtexture_t *viewcolortexture, int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5318 {
5319         uint64_t permutation;
5320         float uservecs[4][4];
5321         rtexture_t *viewtexture;
5322         rtexture_t *bloomtexture;
5323
5324         R_EntityMatrix(&identitymatrix);
5325
5326         if (r_fb.bloomwidth)
5327         {
5328                 // make the bloom texture
5329                 R_Bloom_MakeTexture();
5330         }
5331
5332 #if _MSC_VER >= 1400
5333 #define sscanf sscanf_s
5334 #endif
5335         memset(uservecs, 0, sizeof(uservecs));
5336         if (r_glsl_postprocess_uservec1_enable.integer)
5337                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5338         if (r_glsl_postprocess_uservec2_enable.integer)
5339                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5340         if (r_glsl_postprocess_uservec3_enable.integer)
5341                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5342         if (r_glsl_postprocess_uservec4_enable.integer)
5343                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5344
5345         // render to the screen fbo
5346         R_ResetViewRendering2D(fbo, depthtexture, colortexture, x, y, width, height);
5347         GL_Color(1, 1, 1, 1);
5348         GL_BlendFunc(GL_ONE, GL_ZERO);
5349
5350         viewtexture = viewcolortexture;
5351         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5352
5353         if (r_rendertarget_debug.integer >= 0)
5354         {
5355                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5356                 if (rt && rt->colortexture[0])
5357                 {
5358                         viewtexture = rt->colortexture[0];
5359                         bloomtexture = NULL;
5360                 }
5361         }
5362
5363         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5364         switch(vid.renderpath)
5365         {
5366         case RENDERPATH_GL32:
5367         case RENDERPATH_GLES2:
5368                 permutation =
5369                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5370                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5371                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5372                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5373                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5374                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5375                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5376                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5377                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5378                 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]);
5379                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5380                 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]);
5381                 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]);
5382                 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]);
5383                 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]);
5384                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5385                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5386                 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);
5387                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5388                 break;
5389         }
5390         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5391         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5392 }
5393
5394 matrix4x4_t r_waterscrollmatrix;
5395
5396 void R_UpdateFog(void)
5397 {
5398         // Nehahra fog
5399         if (gamemode == GAME_NEHAHRA)
5400         {
5401                 if (gl_fogenable.integer)
5402                 {
5403                         r_refdef.oldgl_fogenable = true;
5404                         r_refdef.fog_density = gl_fogdensity.value;
5405                         r_refdef.fog_red = gl_fogred.value;
5406                         r_refdef.fog_green = gl_foggreen.value;
5407                         r_refdef.fog_blue = gl_fogblue.value;
5408                         r_refdef.fog_alpha = 1;
5409                         r_refdef.fog_start = 0;
5410                         r_refdef.fog_end = gl_skyclip.value;
5411                         r_refdef.fog_height = 1<<30;
5412                         r_refdef.fog_fadedepth = 128;
5413                 }
5414                 else if (r_refdef.oldgl_fogenable)
5415                 {
5416                         r_refdef.oldgl_fogenable = false;
5417                         r_refdef.fog_density = 0;
5418                         r_refdef.fog_red = 0;
5419                         r_refdef.fog_green = 0;
5420                         r_refdef.fog_blue = 0;
5421                         r_refdef.fog_alpha = 0;
5422                         r_refdef.fog_start = 0;
5423                         r_refdef.fog_end = 0;
5424                         r_refdef.fog_height = 1<<30;
5425                         r_refdef.fog_fadedepth = 128;
5426                 }
5427         }
5428
5429         // fog parms
5430         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5431         r_refdef.fog_start = max(0, r_refdef.fog_start);
5432         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5433
5434         if (r_refdef.fog_density && r_drawfog.integer)
5435         {
5436                 r_refdef.fogenabled = true;
5437                 // this is the point where the fog reaches 0.9986 alpha, which we
5438                 // consider a good enough cutoff point for the texture
5439                 // (0.9986 * 256 == 255.6)
5440                 if (r_fog_exp2.integer)
5441                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5442                 else
5443                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5444                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5445                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5446                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5447                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5448                         R_BuildFogHeightTexture();
5449                 // fog color was already set
5450                 // update the fog texture
5451                 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)
5452                         R_BuildFogTexture();
5453                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5454                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5455         }
5456         else
5457                 r_refdef.fogenabled = false;
5458
5459         // fog color
5460         if (r_refdef.fog_density)
5461         {
5462                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5463                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5464                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5465
5466                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5467                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5468                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5469                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5470
5471                 {
5472                         vec3_t fogvec;
5473                         VectorCopy(r_refdef.fogcolor, fogvec);
5474                         //   color.rgb *= ContrastBoost * SceneBrightness;
5475                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5476                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5477                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5478                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5479                 }
5480         }
5481 }
5482
5483 void R_UpdateVariables(void)
5484 {
5485         R_Textures_Frame();
5486
5487         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5488
5489         r_refdef.farclip = r_farclip_base.value;
5490         if (r_refdef.scene.worldmodel)
5491                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5492         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5493
5494         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5495                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5496         r_refdef.polygonfactor = 0;
5497         r_refdef.polygonoffset = 0;
5498
5499         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5500         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5501         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5502         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5503         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5504         if (r_refdef.scene.worldmodel)
5505         {
5506                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5507
5508                 // Apply the default lightstyle to the lightmap even on q3bsp
5509                 if (cl.worldmodel && cl.worldmodel->type == mod_brushq3) {
5510                         r_refdef.scene.lightmapintensity *= r_refdef.scene.rtlightstylevalue[0];
5511                 }
5512         }
5513         if (r_showsurfaces.integer)
5514         {
5515                 r_refdef.scene.rtworld = false;
5516                 r_refdef.scene.rtworldshadows = false;
5517                 r_refdef.scene.rtdlight = false;
5518                 r_refdef.scene.rtdlightshadows = false;
5519                 r_refdef.scene.lightmapintensity = 0;
5520         }
5521
5522         r_gpuskeletal = false;
5523         switch(vid.renderpath)
5524         {
5525         case RENDERPATH_GL32:
5526                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5527         case RENDERPATH_GLES2:
5528                 if(!vid_gammatables_trivial)
5529                 {
5530                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5531                         {
5532                                 // build GLSL gamma texture
5533 #define RAMPWIDTH 256
5534                                 unsigned short ramp[RAMPWIDTH * 3];
5535                                 unsigned char rampbgr[RAMPWIDTH][4];
5536                                 int i;
5537
5538                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5539
5540                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5541                                 for(i = 0; i < RAMPWIDTH; ++i)
5542                                 {
5543                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5544                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5545                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5546                                         rampbgr[i][3] = 0;
5547                                 }
5548                                 if (r_texture_gammaramps)
5549                                 {
5550                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5551                                 }
5552                                 else
5553                                 {
5554                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5555                                 }
5556                         }
5557                 }
5558                 else
5559                 {
5560                         // remove GLSL gamma texture
5561                 }
5562                 break;
5563         }
5564 }
5565
5566 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5567 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5568 /*
5569 ================
5570 R_SelectScene
5571 ================
5572 */
5573 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5574         if( scenetype != r_currentscenetype ) {
5575                 // store the old scenetype
5576                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5577                 r_currentscenetype = scenetype;
5578                 // move in the new scene
5579                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5580         }
5581 }
5582
5583 /*
5584 ================
5585 R_GetScenePointer
5586 ================
5587 */
5588 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5589 {
5590         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5591         if( scenetype == r_currentscenetype ) {
5592                 return &r_refdef.scene;
5593         } else {
5594                 return &r_scenes_store[ scenetype ];
5595         }
5596 }
5597
5598 static int R_SortEntities_Compare(const void *ap, const void *bp)
5599 {
5600         const entity_render_t *a = *(const entity_render_t **)ap;
5601         const entity_render_t *b = *(const entity_render_t **)bp;
5602
5603         // 1. compare model
5604         if(a->model < b->model)
5605                 return -1;
5606         if(a->model > b->model)
5607                 return +1;
5608
5609         // 2. compare skin
5610         // TODO possibly calculate the REAL skinnum here first using
5611         // skinscenes?
5612         if(a->skinnum < b->skinnum)
5613                 return -1;
5614         if(a->skinnum > b->skinnum)
5615                 return +1;
5616
5617         // everything we compared is equal
5618         return 0;
5619 }
5620 static void R_SortEntities(void)
5621 {
5622         // below or equal 2 ents, sorting never gains anything
5623         if(r_refdef.scene.numentities <= 2)
5624                 return;
5625         // sort
5626         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5627 }
5628
5629 /*
5630 ================
5631 R_RenderView
5632 ================
5633 */
5634 extern cvar_t r_shadow_bouncegrid;
5635 extern cvar_t v_isometric;
5636 extern void V_MakeViewIsometric(void);
5637 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5638 {
5639         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5640         int viewfbo = 0;
5641         rtexture_t *viewdepthtexture = NULL;
5642         rtexture_t *viewcolortexture = NULL;
5643         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5644         qbool skipblend;
5645
5646         // finish any 2D rendering that was queued
5647         DrawQ_Finish();
5648
5649         if (r_timereport_active)
5650                 R_TimeReport("start");
5651         r_textureframe++; // used only by R_GetCurrentTexture
5652         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5653
5654         if(R_CompileShader_CheckStaticParms())
5655                 R_GLSL_Restart_f(cmd_local);
5656
5657         if (!r_drawentities.integer)
5658                 r_refdef.scene.numentities = 0;
5659         else if (r_sortentities.integer)
5660                 R_SortEntities();
5661
5662         R_AnimCache_ClearCache();
5663
5664         /* adjust for stereo display */
5665         if(R_Stereo_Active())
5666         {
5667                 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);
5668                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5669         }
5670
5671         if (r_refdef.view.isoverlay)
5672         {
5673                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5674                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5675                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5676                 R_TimeReport("depthclear");
5677
5678                 r_refdef.view.showdebug = false;
5679
5680                 r_fb.water.enabled = false;
5681                 r_fb.water.numwaterplanes = 0;
5682
5683                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5684
5685                 r_refdef.view.matrix = originalmatrix;
5686
5687                 CHECKGLERROR
5688                 return;
5689         }
5690
5691         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5692         {
5693                 r_refdef.view.matrix = originalmatrix;
5694                 return;
5695         }
5696
5697         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5698         if (v_isometric.integer && r_refdef.view.ismain)
5699                 V_MakeViewIsometric();
5700
5701         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5702
5703         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5704                 // in sRGB fallback, behave similar to true sRGB: convert this
5705                 // value from linear to sRGB
5706                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5707
5708         R_RenderView_UpdateViewVectors();
5709
5710         R_Shadow_UpdateWorldLightSelection();
5711
5712         // this will set up r_fb.rt_screen
5713         R_Bloom_StartFrame();
5714
5715         // apply bloom brightness offset
5716         if(r_fb.rt_bloom)
5717                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5718
5719         skipblend = R_BlendView_IsTrivial(r_fb.rt_screen->texturewidth, r_fb.rt_screen->textureheight, width, height);
5720         if (skipblend)
5721         {
5722                 // Render to the screen right away.
5723                 viewfbo = fbo;
5724                 viewdepthtexture = depthtexture;
5725                 viewcolortexture = colortexture;
5726                 viewx = x;
5727                 viewy = y;
5728                 viewwidth = width;
5729                 viewheight = height;
5730         }
5731         else if (r_fb.rt_screen)
5732         {
5733                 // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5734                 viewfbo = r_fb.rt_screen->fbo;
5735                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5736                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5737                 viewx = 0;
5738                 viewy = 0;
5739                 viewwidth = r_fb.rt_screen->texturewidth;
5740                 viewheight = r_fb.rt_screen->textureheight;
5741         }
5742
5743         R_Water_StartFrame(viewwidth, viewheight);
5744
5745         CHECKGLERROR
5746         if (r_timereport_active)
5747                 R_TimeReport("viewsetup");
5748
5749         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5750
5751         // clear the whole fbo every frame - otherwise the driver will consider
5752         // it to be an inter-frame texture and stall in multi-gpu configurations
5753         if (r_fb.rt_screen)
5754                 GL_ScissorTest(false);
5755         R_ClearScreen(r_refdef.fogenabled);
5756         if (r_timereport_active)
5757                 R_TimeReport("viewclear");
5758
5759         r_refdef.view.clear = true;
5760
5761         r_refdef.view.showdebug = true;
5762
5763         R_View_Update(NULL);
5764         if (r_timereport_active)
5765                 R_TimeReport("visibility");
5766
5767         R_AnimCache_CacheVisibleEntities();
5768         if (r_timereport_active)
5769                 R_TimeReport("animcache");
5770
5771         R_Shadow_UpdateBounceGridTexture();
5772         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5773
5774         r_fb.water.numwaterplanes = 0;
5775         if (r_fb.water.enabled)
5776                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5777
5778         // for the actual view render we use scissoring a fair amount, so scissor
5779         // test needs to be on
5780         if (r_fb.rt_screen)
5781                 GL_ScissorTest(true);
5782         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
5783         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5784         r_fb.water.numwaterplanes = 0;
5785
5786         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5787         GL_ScissorTest(false);
5788
5789         R_MotionBlurView(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5790         if (!skipblend)
5791                 R_BlendView(viewcolortexture, fbo, depthtexture, colortexture, x, y, width, height);
5792         if (r_timereport_active)
5793                 R_TimeReport("blendview");
5794
5795         r_refdef.view.matrix = originalmatrix;
5796
5797         CHECKGLERROR
5798
5799         // go back to 2d rendering
5800         DrawQ_Start();
5801 }
5802
5803 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5804 {
5805         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5806         {
5807                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5808                 if (r_timereport_active)
5809                         R_TimeReport("waterworld");
5810         }
5811
5812         // don't let sound skip if going slow
5813         if (r_refdef.scene.extraupdate)
5814                 S_ExtraUpdate ();
5815
5816         R_DrawModelsAddWaterPlanes();
5817         if (r_timereport_active)
5818                 R_TimeReport("watermodels");
5819
5820         if (r_fb.water.numwaterplanes)
5821         {
5822                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5823                 if (r_timereport_active)
5824                         R_TimeReport("waterscenes");
5825         }
5826 }
5827
5828 extern cvar_t cl_locs_show;
5829 static void R_DrawLocs(void);
5830 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5831 static void R_DrawModelDecals(void);
5832 extern qbool r_shadow_usingdeferredprepass;
5833 extern int r_shadow_shadowmapatlas_modelshadows_size;
5834 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5835 {
5836         qbool shadowmapping = false;
5837
5838         if (r_timereport_active)
5839                 R_TimeReport("beginscene");
5840
5841         r_refdef.stats[r_stat_renders]++;
5842
5843         R_UpdateFog();
5844
5845         // don't let sound skip if going slow
5846         if (r_refdef.scene.extraupdate)
5847                 S_ExtraUpdate ();
5848
5849         R_MeshQueue_BeginScene();
5850
5851         R_SkyStartFrame();
5852
5853         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);
5854
5855         if (r_timereport_active)
5856                 R_TimeReport("skystartframe");
5857
5858         if (cl.csqc_vidvars.drawworld)
5859         {
5860                 // don't let sound skip if going slow
5861                 if (r_refdef.scene.extraupdate)
5862                         S_ExtraUpdate ();
5863
5864                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5865                 {
5866                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5867                         if (r_timereport_active)
5868                                 R_TimeReport("worldsky");
5869                 }
5870
5871                 if (R_DrawBrushModelsSky() && r_timereport_active)
5872                         R_TimeReport("bmodelsky");
5873
5874                 if (skyrendermasked && skyrenderlater)
5875                 {
5876                         // we have to force off the water clipping plane while rendering sky
5877                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5878                         R_Sky();
5879                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5880                         if (r_timereport_active)
5881                                 R_TimeReport("sky");
5882                 }
5883         }
5884
5885         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5886         r_shadow_viewfbo = viewfbo;
5887         r_shadow_viewdepthtexture = viewdepthtexture;
5888         r_shadow_viewcolortexture = viewcolortexture;
5889         r_shadow_viewx = viewx;
5890         r_shadow_viewy = viewy;
5891         r_shadow_viewwidth = viewwidth;
5892         r_shadow_viewheight = viewheight;
5893
5894         R_Shadow_PrepareModelShadows();
5895         R_Shadow_PrepareLights();
5896         if (r_timereport_active)
5897                 R_TimeReport("preparelights");
5898
5899         // render all the shadowmaps that will be used for this view
5900         shadowmapping = R_Shadow_ShadowMappingEnabled();
5901         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5902         {
5903                 R_Shadow_DrawShadowMaps();
5904                 if (r_timereport_active)
5905                         R_TimeReport("shadowmaps");
5906         }
5907
5908         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5909         if (r_shadow_usingdeferredprepass)
5910                 R_Shadow_DrawPrepass();
5911
5912         // now we begin the forward pass of the view render
5913         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5914         {
5915                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5916                 if (r_timereport_active)
5917                         R_TimeReport("worlddepth");
5918         }
5919         if (r_depthfirst.integer >= 2)
5920         {
5921                 R_DrawModelsDepth();
5922                 if (r_timereport_active)
5923                         R_TimeReport("modeldepth");
5924         }
5925
5926         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5927         {
5928                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5929                 if (r_timereport_active)
5930                         R_TimeReport("world");
5931         }
5932
5933         // don't let sound skip if going slow
5934         if (r_refdef.scene.extraupdate)
5935                 S_ExtraUpdate ();
5936
5937         R_DrawModels();
5938         if (r_timereport_active)
5939                 R_TimeReport("models");
5940
5941         // don't let sound skip if going slow
5942         if (r_refdef.scene.extraupdate)
5943                 S_ExtraUpdate ();
5944
5945         if (!r_shadow_usingdeferredprepass)
5946         {
5947                 R_Shadow_DrawLights();
5948                 if (r_timereport_active)
5949                         R_TimeReport("rtlights");
5950         }
5951
5952         // don't let sound skip if going slow
5953         if (r_refdef.scene.extraupdate)
5954                 S_ExtraUpdate ();
5955
5956         if (cl.csqc_vidvars.drawworld)
5957         {
5958                 R_DrawModelDecals();
5959                 if (r_timereport_active)
5960                         R_TimeReport("modeldecals");
5961
5962                 R_DrawParticles();
5963                 if (r_timereport_active)
5964                         R_TimeReport("particles");
5965
5966                 R_DrawExplosions();
5967                 if (r_timereport_active)
5968                         R_TimeReport("explosions");
5969         }
5970
5971         if (r_refdef.view.showdebug)
5972         {
5973                 if (cl_locs_show.integer)
5974                 {
5975                         R_DrawLocs();
5976                         if (r_timereport_active)
5977                                 R_TimeReport("showlocs");
5978                 }
5979
5980                 if (r_drawportals.integer)
5981                 {
5982                         R_DrawPortals();
5983                         if (r_timereport_active)
5984                                 R_TimeReport("portals");
5985                 }
5986
5987                 if (r_showbboxes_client.value > 0)
5988                 {
5989                         R_DrawEntityBBoxes(CLVM_prog);
5990                         if (r_timereport_active)
5991                                 R_TimeReport("clbboxes");
5992                 }
5993                 if (r_showbboxes.value > 0)
5994                 {
5995                         R_DrawEntityBBoxes(SVVM_prog);
5996                         if (r_timereport_active)
5997                                 R_TimeReport("svbboxes");
5998                 }
5999         }
6000
6001         if (r_transparent.integer)
6002         {
6003                 R_MeshQueue_RenderTransparent();
6004                 if (r_timereport_active)
6005                         R_TimeReport("drawtrans");
6006         }
6007
6008         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))
6009         {
6010                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6011                 if (r_timereport_active)
6012                         R_TimeReport("worlddebug");
6013                 R_DrawModelsDebug();
6014                 if (r_timereport_active)
6015                         R_TimeReport("modeldebug");
6016         }
6017
6018         if (cl.csqc_vidvars.drawworld)
6019         {
6020                 R_Shadow_DrawCoronas();
6021                 if (r_timereport_active)
6022                         R_TimeReport("coronas");
6023         }
6024
6025         // don't let sound skip if going slow
6026         if (r_refdef.scene.extraupdate)
6027                 S_ExtraUpdate ();
6028 }
6029
6030 static const unsigned short bboxelements[36] =
6031 {
6032         5, 1, 3, 5, 3, 7,
6033         6, 2, 0, 6, 0, 4,
6034         7, 3, 2, 7, 2, 6,
6035         4, 0, 1, 4, 1, 5,
6036         4, 5, 7, 4, 7, 6,
6037         1, 0, 2, 1, 2, 3,
6038 };
6039
6040 #define BBOXEDGES 13
6041 static const float bboxedges[BBOXEDGES][6] =
6042 {
6043         // whole box
6044         { 0, 0, 0, 1, 1, 1 },
6045         // bottom edges
6046         { 0, 0, 0, 0, 1, 0 },
6047         { 0, 0, 0, 1, 0, 0 },
6048         { 0, 1, 0, 1, 1, 0 },
6049         { 1, 0, 0, 1, 1, 0 },
6050         // top edges
6051         { 0, 0, 1, 0, 1, 1 },
6052         { 0, 0, 1, 1, 0, 1 },
6053         { 0, 1, 1, 1, 1, 1 },
6054         { 1, 0, 1, 1, 1, 1 },
6055         // vertical edges
6056         { 0, 0, 0, 0, 0, 1 },
6057         { 1, 0, 0, 1, 0, 1 },
6058         { 0, 1, 0, 0, 1, 1 },
6059         { 1, 1, 0, 1, 1, 1 },
6060 };
6061
6062 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6063 {
6064         int numvertices = BBOXEDGES * 8;
6065         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6066         int numtriangles = BBOXEDGES * 12;
6067         unsigned short elements[BBOXEDGES * 36];
6068         int i, edge;
6069         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6070
6071         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6072
6073         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6074         GL_DepthMask(false);
6075         GL_DepthRange(0, 1);
6076         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6077
6078         for (edge = 0; edge < BBOXEDGES; edge++)
6079         {
6080                 for (i = 0; i < 3; i++)
6081                 {
6082                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6083                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6084                 }
6085                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6086                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6087                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6088                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6089                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6090                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6091                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6092                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6093                 for (i = 0; i < 36; i++)
6094                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6095         }
6096         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6097         if (r_refdef.fogenabled)
6098         {
6099                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6100                 {
6101                         f1 = RSurf_FogVertex(v);
6102                         f2 = 1 - f1;
6103                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6104                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6105                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6106                 }
6107         }
6108         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6109         R_Mesh_ResetTextureState();
6110         R_SetupShader_Generic_NoTexture(false, false);
6111         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6112 }
6113
6114 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6115 {
6116         // hacky overloading of the parameters
6117         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6118         int i;
6119         float color[4];
6120         prvm_edict_t *edict;
6121
6122         GL_CullFace(GL_NONE);
6123         R_SetupShader_Generic_NoTexture(false, false);
6124
6125         for (i = 0;i < numsurfaces;i++)
6126         {
6127                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6128                 switch ((int)PRVM_serveredictfloat(edict, solid))
6129                 {
6130                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6131                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6132                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6133                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6134                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6135                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6136                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6137                 }
6138                 if (prog == CLVM_prog)
6139                         color[3] *= r_showbboxes_client.value;
6140                 else
6141                         color[3] *= r_showbboxes.value;
6142                 color[3] = bound(0, color[3], 1);
6143                 GL_DepthTest(!r_showdisabledepthtest.integer);
6144                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6145         }
6146 }
6147
6148 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6149 {
6150         int i;
6151         prvm_edict_t *edict;
6152         vec3_t center;
6153
6154         if (prog == NULL)
6155                 return;
6156
6157         for (i = 0; i < prog->num_edicts; i++)
6158         {
6159                 edict = PRVM_EDICT_NUM(i);
6160                 if (edict->free)
6161                         continue;
6162                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6163                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6164                         continue;
6165                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6166                         continue;
6167                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6168                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6169         }
6170 }
6171
6172 static const int nomodelelement3i[24] =
6173 {
6174         5, 2, 0,
6175         5, 1, 2,
6176         5, 0, 3,
6177         5, 3, 1,
6178         0, 2, 4,
6179         2, 1, 4,
6180         3, 0, 4,
6181         1, 3, 4
6182 };
6183
6184 static const unsigned short nomodelelement3s[24] =
6185 {
6186         5, 2, 0,
6187         5, 1, 2,
6188         5, 0, 3,
6189         5, 3, 1,
6190         0, 2, 4,
6191         2, 1, 4,
6192         3, 0, 4,
6193         1, 3, 4
6194 };
6195
6196 static const float nomodelvertex3f[6*3] =
6197 {
6198         -16,   0,   0,
6199          16,   0,   0,
6200           0, -16,   0,
6201           0,  16,   0,
6202           0,   0, -16,
6203           0,   0,  16
6204 };
6205
6206 static const float nomodelcolor4f[6*4] =
6207 {
6208         0.0f, 0.0f, 0.5f, 1.0f,
6209         0.0f, 0.0f, 0.5f, 1.0f,
6210         0.0f, 0.5f, 0.0f, 1.0f,
6211         0.0f, 0.5f, 0.0f, 1.0f,
6212         0.5f, 0.0f, 0.0f, 1.0f,
6213         0.5f, 0.0f, 0.0f, 1.0f
6214 };
6215
6216 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6217 {
6218         int i;
6219         float f1, f2, *c;
6220         float color4f[6*4];
6221
6222         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);
6223
6224         // this is only called once per entity so numsurfaces is always 1, and
6225         // surfacelist is always {0}, so this code does not handle batches
6226
6227         if (rsurface.ent_flags & RENDER_ADDITIVE)
6228         {
6229                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6230                 GL_DepthMask(false);
6231         }
6232         else if (ent->alpha < 1)
6233         {
6234                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6235                 GL_DepthMask(false);
6236         }
6237         else
6238         {
6239                 GL_BlendFunc(GL_ONE, GL_ZERO);
6240                 GL_DepthMask(true);
6241         }
6242         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6243         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6244         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6245         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6246         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6247         for (i = 0, c = color4f;i < 6;i++, c += 4)
6248         {
6249                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6250                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6251                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6252                 c[3] *= ent->alpha;
6253         }
6254         if (r_refdef.fogenabled)
6255         {
6256                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6257                 {
6258                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6259                         f2 = 1 - f1;
6260                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6261                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6262                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6263                 }
6264         }
6265 //      R_Mesh_ResetTextureState();
6266         R_SetupShader_Generic_NoTexture(false, false);
6267         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6268         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6269 }
6270
6271 void R_DrawNoModel(entity_render_t *ent)
6272 {
6273         vec3_t org;
6274         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6275         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6276                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6277         else
6278                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6279 }
6280
6281 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6282 {
6283         vec3_t right1, right2, diff, normal;
6284
6285         VectorSubtract (org2, org1, normal);
6286
6287         // calculate 'right' vector for start
6288         VectorSubtract (r_refdef.view.origin, org1, diff);
6289         CrossProduct (normal, diff, right1);
6290         VectorNormalize (right1);
6291
6292         // calculate 'right' vector for end
6293         VectorSubtract (r_refdef.view.origin, org2, diff);
6294         CrossProduct (normal, diff, right2);
6295         VectorNormalize (right2);
6296
6297         vert[ 0] = org1[0] + width * right1[0];
6298         vert[ 1] = org1[1] + width * right1[1];
6299         vert[ 2] = org1[2] + width * right1[2];
6300         vert[ 3] = org1[0] - width * right1[0];
6301         vert[ 4] = org1[1] - width * right1[1];
6302         vert[ 5] = org1[2] - width * right1[2];
6303         vert[ 6] = org2[0] - width * right2[0];
6304         vert[ 7] = org2[1] - width * right2[1];
6305         vert[ 8] = org2[2] - width * right2[2];
6306         vert[ 9] = org2[0] + width * right2[0];
6307         vert[10] = org2[1] + width * right2[1];
6308         vert[11] = org2[2] + width * right2[2];
6309 }
6310
6311 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)
6312 {
6313         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6314         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6315         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6316         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6317         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6318         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6319         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6320         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6321         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6322         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6323         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6324         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6325 }
6326
6327 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6328 {
6329         int i;
6330         float *vertex3f;
6331         float v[3];
6332         VectorSet(v, x, y, z);
6333         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6334                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6335                         break;
6336         if (i == mesh->numvertices)
6337         {
6338                 if (mesh->numvertices < mesh->maxvertices)
6339                 {
6340                         VectorCopy(v, vertex3f);
6341                         mesh->numvertices++;
6342                 }
6343                 return mesh->numvertices;
6344         }
6345         else
6346                 return i;
6347 }
6348
6349 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6350 {
6351         int i;
6352         int *e, element[3];
6353         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6354         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6355         e = mesh->element3i + mesh->numtriangles * 3;
6356         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6357         {
6358                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6359                 if (mesh->numtriangles < mesh->maxtriangles)
6360                 {
6361                         *e++ = element[0];
6362                         *e++ = element[1];
6363                         *e++ = element[2];
6364                         mesh->numtriangles++;
6365                 }
6366                 element[1] = element[2];
6367         }
6368 }
6369
6370 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6371 {
6372         int i;
6373         int *e, element[3];
6374         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6375         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6376         e = mesh->element3i + mesh->numtriangles * 3;
6377         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6378         {
6379                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6380                 if (mesh->numtriangles < mesh->maxtriangles)
6381                 {
6382                         *e++ = element[0];
6383                         *e++ = element[1];
6384                         *e++ = element[2];
6385                         mesh->numtriangles++;
6386                 }
6387                 element[1] = element[2];
6388         }
6389 }
6390
6391 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6392 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6393 {
6394         int planenum, planenum2;
6395         int w;
6396         int tempnumpoints;
6397         mplane_t *plane, *plane2;
6398         double maxdist;
6399         double temppoints[2][256*3];
6400         // figure out how large a bounding box we need to properly compute this brush
6401         maxdist = 0;
6402         for (w = 0;w < numplanes;w++)
6403                 maxdist = max(maxdist, fabs(planes[w].dist));
6404         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6405         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6406         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6407         {
6408                 w = 0;
6409                 tempnumpoints = 4;
6410                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6411                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6412                 {
6413                         if (planenum2 == planenum)
6414                                 continue;
6415                         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);
6416                         w = !w;
6417                 }
6418                 if (tempnumpoints < 3)
6419                         continue;
6420                 // generate elements forming a triangle fan for this polygon
6421                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6422         }
6423 }
6424
6425 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6426 {
6427         if(parms[0] == 0 && parms[1] == 0)
6428                 return false;
6429         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6430                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6431                         return false;
6432         return true;
6433 }
6434
6435 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6436 {
6437         double index, f;
6438         index = parms[2] + rsurface.shadertime * parms[3];
6439         index -= floor(index);
6440         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6441         {
6442         default:
6443         case Q3WAVEFUNC_NONE:
6444         case Q3WAVEFUNC_NOISE:
6445         case Q3WAVEFUNC_COUNT:
6446                 f = 0;
6447                 break;
6448         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6449         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6450         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6451         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6452         case Q3WAVEFUNC_TRIANGLE:
6453                 index *= 4;
6454                 f = index - floor(index);
6455                 if (index < 1)
6456                 {
6457                         // f = f;
6458                 }
6459                 else if (index < 2)
6460                         f = 1 - f;
6461                 else if (index < 3)
6462                         f = -f;
6463                 else
6464                         f = -(1 - f);
6465                 break;
6466         }
6467         f = parms[0] + parms[1] * f;
6468         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6469                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6470         return (float) f;
6471 }
6472
6473 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6474 {
6475         int w, h, idx;
6476         float shadertime;
6477         float f;
6478         float offsetd[2];
6479         float tcmat[12];
6480         matrix4x4_t matrix, temp;
6481         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6482         // it's better to have one huge fixup every 9 hours than gradual
6483         // degradation over time which looks consistently bad after many hours.
6484         //
6485         // tcmod scroll in particular suffers from this degradation which can't be
6486         // effectively worked around even with floor() tricks because we don't
6487         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6488         // a workaround involving floor() would be incorrect anyway...
6489         shadertime = rsurface.shadertime;
6490         if (shadertime >= 32768.0f)
6491                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6492         switch(tcmod->tcmod)
6493         {
6494                 case Q3TCMOD_COUNT:
6495                 case Q3TCMOD_NONE:
6496                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6497                                 matrix = r_waterscrollmatrix;
6498                         else
6499                                 matrix = identitymatrix;
6500                         break;
6501                 case Q3TCMOD_ENTITYTRANSLATE:
6502                         // this is used in Q3 to allow the gamecode to control texcoord
6503                         // scrolling on the entity, which is not supported in darkplaces yet.
6504                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6505                         break;
6506                 case Q3TCMOD_ROTATE:
6507                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6508                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6509                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6510                         break;
6511                 case Q3TCMOD_SCALE:
6512                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6513                         break;
6514                 case Q3TCMOD_SCROLL:
6515                         // this particular tcmod is a "bug for bug" compatible one with regards to
6516                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6517                         // specifically did the wrapping and so we must mimic that...
6518                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6519                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6520                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6521                         break;
6522                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6523                         w = (int) tcmod->parms[0];
6524                         h = (int) tcmod->parms[1];
6525                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6526                         f = f - floor(f);
6527                         idx = (int) floor(f * w * h);
6528                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6529                         break;
6530                 case Q3TCMOD_STRETCH:
6531                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6532                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6533                         break;
6534                 case Q3TCMOD_TRANSFORM:
6535                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6536                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6537                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6538                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6539                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6540                         break;
6541                 case Q3TCMOD_TURBULENT:
6542                         // this is handled in the RSurf_PrepareVertices function
6543                         matrix = identitymatrix;
6544                         break;
6545         }
6546         temp = *texmatrix;
6547         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6548 }
6549
6550 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6551 {
6552         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6553         char name[MAX_QPATH];
6554         skinframe_t *skinframe;
6555         unsigned char pixels[296*194];
6556         dp_strlcpy(cache->name, skinname, sizeof(cache->name));
6557         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6558         if (developer_loading.integer)
6559                 Con_Printf("loading %s\n", name);
6560         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6561         if (!skinframe || !skinframe->base)
6562         {
6563                 unsigned char *f;
6564                 fs_offset_t filesize;
6565                 skinframe = NULL;
6566                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6567                 if (f)
6568                 {
6569                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6570                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6571                         Mem_Free(f);
6572                 }
6573         }
6574         cache->skinframe = skinframe;
6575 }
6576
6577 texture_t *R_GetCurrentTexture(texture_t *t)
6578 {
6579         int i, q;
6580         const entity_render_t *ent = rsurface.entity;
6581         model_t *model = ent->model; // when calling this, ent must not be NULL
6582         q3shaderinfo_layer_tcmod_t *tcmod;
6583         float specularscale = 0.0f;
6584
6585         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6586                 return t->currentframe;
6587         t->update_lastrenderframe = r_textureframe;
6588         t->update_lastrenderentity = (void *)ent;
6589
6590         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6591                 t->camera_entity = ent->entitynumber;
6592         else
6593                 t->camera_entity = 0;
6594
6595         // switch to an alternate material if this is a q1bsp animated material
6596         {
6597                 texture_t *texture = t;
6598                 int s = rsurface.ent_skinnum;
6599                 if ((unsigned int)s >= (unsigned int)model->numskins)
6600                         s = 0;
6601                 if (model->skinscenes)
6602                 {
6603                         if (model->skinscenes[s].framecount > 1)
6604                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6605                         else
6606                                 s = model->skinscenes[s].firstframe;
6607                 }
6608                 if (s > 0)
6609                         t = t + s * model->num_surfaces;
6610                 if (t->animated)
6611                 {
6612                         // use an alternate animation if the entity's frame is not 0,
6613                         // and only if the texture has an alternate animation
6614                         if (t->animated == 2) // q2bsp
6615                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6616                         else if (rsurface.ent_alttextures && t->anim_total[1])
6617                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6618                         else
6619                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6620                 }
6621                 texture->currentframe = t;
6622         }
6623
6624         // update currentskinframe to be a qw skin or animation frame
6625         if (rsurface.ent_qwskin >= 0)
6626         {
6627                 i = rsurface.ent_qwskin;
6628                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6629                 {
6630                         r_qwskincache_size = cl.maxclients;
6631                         if (r_qwskincache)
6632                                 Mem_Free(r_qwskincache);
6633                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6634                 }
6635                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6636                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6637                 t->currentskinframe = r_qwskincache[i].skinframe;
6638                 if (t->materialshaderpass && t->currentskinframe == NULL)
6639                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6640         }
6641         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6642                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6643         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6644                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6645
6646         t->currentmaterialflags = t->basematerialflags;
6647         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6648         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6649                 t->currentalpha *= r_wateralpha.value;
6650         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6651                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6652         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6653                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6654
6655         // decide on which type of lighting to use for this surface
6656         if (rsurface.entity->render_modellight_forced)
6657                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6658         if (rsurface.entity->render_rtlight_disabled)
6659                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6660         if (rsurface.entity->render_lightgrid)
6661                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6662         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6663         {
6664                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6665                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6666                 for (q = 0; q < 3; q++)
6667                 {
6668                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6669                         t->render_modellight_lightdir_world[q] = q == 2;
6670                         t->render_modellight_lightdir_local[q] = q == 2;
6671                         t->render_modellight_ambient[q] = 1;
6672                         t->render_modellight_diffuse[q] = 0;
6673                         t->render_modellight_specular[q] = 0;
6674                         t->render_lightmap_ambient[q] = 0;
6675                         t->render_lightmap_diffuse[q] = 0;
6676                         t->render_lightmap_specular[q] = 0;
6677                         t->render_rtlight_diffuse[q] = 0;
6678                         t->render_rtlight_specular[q] = 0;
6679                 }
6680         }
6681         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6682         {
6683                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6684                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6685                 for (q = 0; q < 3; q++)
6686                 {
6687                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6688                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6689                         t->render_modellight_lightdir_world[q] = q == 2;
6690                         t->render_modellight_lightdir_local[q] = q == 2;
6691                         t->render_modellight_diffuse[q] = 0;
6692                         t->render_modellight_specular[q] = 0;
6693                         t->render_lightmap_ambient[q] = 0;
6694                         t->render_lightmap_diffuse[q] = 0;
6695                         t->render_lightmap_specular[q] = 0;
6696                         t->render_rtlight_diffuse[q] = 0;
6697                         t->render_rtlight_specular[q] = 0;
6698                 }
6699         }
6700         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6701         {
6702                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6703                 for (q = 0; q < 3; q++)
6704                 {
6705                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6706                         t->render_modellight_lightdir_world[q] = q == 2;
6707                         t->render_modellight_lightdir_local[q] = q == 2;
6708                         t->render_modellight_ambient[q] = 0;
6709                         t->render_modellight_diffuse[q] = 0;
6710                         t->render_modellight_specular[q] = 0;
6711                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6712                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6713                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6714                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6715                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6716                 }
6717         }
6718         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6719         {
6720                 // ambient + single direction light (modellight)
6721                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6722                 for (q = 0; q < 3; q++)
6723                 {
6724                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6725                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6726                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6727                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6728                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6729                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6730                         t->render_lightmap_ambient[q] = 0;
6731                         t->render_lightmap_diffuse[q] = 0;
6732                         t->render_lightmap_specular[q] = 0;
6733                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6734                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6735                 }
6736         }
6737         else
6738         {
6739                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6740                 for (q = 0; q < 3; q++)
6741                 {
6742                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6743                         t->render_modellight_lightdir_world[q] = q == 2;
6744                         t->render_modellight_lightdir_local[q] = q == 2;
6745                         t->render_modellight_ambient[q] = 0;
6746                         t->render_modellight_diffuse[q] = 0;
6747                         t->render_modellight_specular[q] = 0;
6748                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6749                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6750                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6751                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6752                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6753                 }
6754         }
6755
6756         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6757         {
6758                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6759                 // attribute, we punt it to the lightmap path and hope for the best,
6760                 // but lighting doesn't work.
6761                 //
6762                 // FIXME: this is fine for effects but CSQC polygons should be subject
6763                 // to lighting.
6764                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6765                 for (q = 0; q < 3; q++)
6766                 {
6767                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6768                         t->render_modellight_lightdir_world[q] = q == 2;
6769                         t->render_modellight_lightdir_local[q] = q == 2;
6770                         t->render_modellight_ambient[q] = 0;
6771                         t->render_modellight_diffuse[q] = 0;
6772                         t->render_modellight_specular[q] = 0;
6773                         t->render_lightmap_ambient[q] = 0;
6774                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6775                         t->render_lightmap_specular[q] = 0;
6776                         t->render_rtlight_diffuse[q] = 0;
6777                         t->render_rtlight_specular[q] = 0;
6778                 }
6779         }
6780
6781         for (q = 0; q < 3; q++)
6782         {
6783                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6784                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6785         }
6786
6787         if (rsurface.ent_flags & RENDER_ADDITIVE)
6788                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6789         else if (t->currentalpha < 1)
6790                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6791         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6792         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6793                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6794         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6795                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6796         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6797                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6798         if (t->backgroundshaderpass)
6799                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6800         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6801         {
6802                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6803                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6804         }
6805         else
6806                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6807         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6808         {
6809                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6810                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6811         }
6812         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6813                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6814
6815         // there is no tcmod
6816         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6817         {
6818                 t->currenttexmatrix = r_waterscrollmatrix;
6819                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6820         }
6821         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6822         {
6823                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6824                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6825         }
6826
6827         if (t->materialshaderpass)
6828                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6829                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6830
6831         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6832         if (t->currentskinframe->qpixels)
6833                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6834         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6835         if (!t->basetexture)
6836                 t->basetexture = r_texture_notexture;
6837         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6838         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6839         t->nmaptexture = t->currentskinframe->nmap;
6840         if (!t->nmaptexture)
6841                 t->nmaptexture = r_texture_blanknormalmap;
6842         t->glosstexture = r_texture_black;
6843         t->glowtexture = t->currentskinframe->glow;
6844         t->fogtexture = t->currentskinframe->fog;
6845         t->reflectmasktexture = t->currentskinframe->reflect;
6846         if (t->backgroundshaderpass)
6847         {
6848                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6849                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6850                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6851                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6852                 t->backgroundglosstexture = r_texture_black;
6853                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6854                 if (!t->backgroundnmaptexture)
6855                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6856                 // make sure that if glow is going to be used, both textures are not NULL
6857                 if (!t->backgroundglowtexture && t->glowtexture)
6858                         t->backgroundglowtexture = r_texture_black;
6859                 if (!t->glowtexture && t->backgroundglowtexture)
6860                         t->glowtexture = r_texture_black;
6861         }
6862         else
6863         {
6864                 t->backgroundbasetexture = r_texture_white;
6865                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6866                 t->backgroundglosstexture = r_texture_black;
6867                 t->backgroundglowtexture = NULL;
6868         }
6869         t->specularpower = r_shadow_glossexponent.value;
6870         // TODO: store reference values for these in the texture?
6871         if (r_shadow_gloss.integer > 0)
6872         {
6873                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6874                 {
6875                         if (r_shadow_glossintensity.value > 0)
6876                         {
6877                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6878                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6879                                 specularscale = r_shadow_glossintensity.value;
6880                         }
6881                 }
6882                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6883                 {
6884                         t->glosstexture = r_texture_white;
6885                         t->backgroundglosstexture = r_texture_white;
6886                         specularscale = r_shadow_gloss2intensity.value;
6887                         t->specularpower = r_shadow_gloss2exponent.value;
6888                 }
6889         }
6890         specularscale *= t->specularscalemod;
6891         t->specularpower *= t->specularpowermod;
6892
6893         // lightmaps mode looks bad with dlights using actual texturing, so turn
6894         // off the colormap and glossmap, but leave the normalmap on as it still
6895         // accurately represents the shading involved
6896         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6897         {
6898                 t->basetexture = r_texture_grey128;
6899                 t->pantstexture = r_texture_black;
6900                 t->shirttexture = r_texture_black;
6901                 if (gl_lightmaps.integer < 2)
6902                         t->nmaptexture = r_texture_blanknormalmap;
6903                 t->glosstexture = r_texture_black;
6904                 t->glowtexture = NULL;
6905                 t->fogtexture = NULL;
6906                 t->reflectmasktexture = NULL;
6907                 t->backgroundbasetexture = NULL;
6908                 if (gl_lightmaps.integer < 2)
6909                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6910                 t->backgroundglosstexture = r_texture_black;
6911                 t->backgroundglowtexture = NULL;
6912                 specularscale = 0;
6913                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6914         }
6915
6916         if (specularscale != 1.0f)
6917         {
6918                 for (q = 0; q < 3; q++)
6919                 {
6920                         t->render_modellight_specular[q] *= specularscale;
6921                         t->render_lightmap_specular[q] *= specularscale;
6922                         t->render_rtlight_specular[q] *= specularscale;
6923                 }
6924         }
6925
6926         t->currentblendfunc[0] = GL_ONE;
6927         t->currentblendfunc[1] = GL_ZERO;
6928         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6929         {
6930                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6931                 t->currentblendfunc[1] = GL_ONE;
6932         }
6933         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6934         {
6935                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6936                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6937         }
6938         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6939         {
6940                 t->currentblendfunc[0] = t->customblendfunc[0];
6941                 t->currentblendfunc[1] = t->customblendfunc[1];
6942         }
6943
6944         return t;
6945 }
6946
6947 rsurfacestate_t rsurface;
6948
6949 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6950 {
6951         model_t *model = ent->model;
6952         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6953         //      return;
6954         rsurface.entity = (entity_render_t *)ent;
6955         rsurface.skeleton = ent->skeleton;
6956         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6957         rsurface.ent_skinnum = ent->skinnum;
6958         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;
6959         rsurface.ent_flags = ent->flags;
6960         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6961                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6962         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6963         rsurface.matrix = ent->matrix;
6964         rsurface.inversematrix = ent->inversematrix;
6965         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6966         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6967         R_EntityMatrix(&rsurface.matrix);
6968         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6969         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6970         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6971         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6972         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6973         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6974         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6975         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6976         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6977         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6978         if (ent->model->brush.submodel && !prepass)
6979         {
6980                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6981                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6982         }
6983         // if the animcache code decided it should use the shader path, skip the deform step
6984         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6985         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6986         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6987         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6988         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6989         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6990         {
6991                 if (ent->animcache_vertex3f)
6992                 {
6993                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6994                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6995                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6996                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6997                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6998                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6999                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7000                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7001                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7002                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7003                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7004                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7005                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7006                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7007                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7008                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7009                 }
7010                 else if (wanttangents)
7011                 {
7012                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7013                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7014                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7015                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7016                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7017                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7018                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7019                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7020                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7021                         rsurface.modelvertex3f_vertexbuffer = NULL;
7022                         rsurface.modelvertex3f_bufferoffset = 0;
7023                         rsurface.modelvertex3f_vertexbuffer = 0;
7024                         rsurface.modelvertex3f_bufferoffset = 0;
7025                         rsurface.modelsvector3f_vertexbuffer = 0;
7026                         rsurface.modelsvector3f_bufferoffset = 0;
7027                         rsurface.modeltvector3f_vertexbuffer = 0;
7028                         rsurface.modeltvector3f_bufferoffset = 0;
7029                         rsurface.modelnormal3f_vertexbuffer = 0;
7030                         rsurface.modelnormal3f_bufferoffset = 0;
7031                 }
7032                 else if (wantnormals)
7033                 {
7034                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7035                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7036                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7037                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7038                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7039                         rsurface.modelsvector3f = NULL;
7040                         rsurface.modeltvector3f = NULL;
7041                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7042                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7043                         rsurface.modelvertex3f_vertexbuffer = NULL;
7044                         rsurface.modelvertex3f_bufferoffset = 0;
7045                         rsurface.modelvertex3f_vertexbuffer = 0;
7046                         rsurface.modelvertex3f_bufferoffset = 0;
7047                         rsurface.modelsvector3f_vertexbuffer = 0;
7048                         rsurface.modelsvector3f_bufferoffset = 0;
7049                         rsurface.modeltvector3f_vertexbuffer = 0;
7050                         rsurface.modeltvector3f_bufferoffset = 0;
7051                         rsurface.modelnormal3f_vertexbuffer = 0;
7052                         rsurface.modelnormal3f_bufferoffset = 0;
7053                 }
7054                 else
7055                 {
7056                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7057                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7058                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7059                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7060                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7061                         rsurface.modelsvector3f = NULL;
7062                         rsurface.modeltvector3f = NULL;
7063                         rsurface.modelnormal3f = NULL;
7064                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7065                         rsurface.modelvertex3f_vertexbuffer = NULL;
7066                         rsurface.modelvertex3f_bufferoffset = 0;
7067                         rsurface.modelvertex3f_vertexbuffer = 0;
7068                         rsurface.modelvertex3f_bufferoffset = 0;
7069                         rsurface.modelsvector3f_vertexbuffer = 0;
7070                         rsurface.modelsvector3f_bufferoffset = 0;
7071                         rsurface.modeltvector3f_vertexbuffer = 0;
7072                         rsurface.modeltvector3f_bufferoffset = 0;
7073                         rsurface.modelnormal3f_vertexbuffer = 0;
7074                         rsurface.modelnormal3f_bufferoffset = 0;
7075                 }
7076                 rsurface.modelgeneratedvertex = true;
7077         }
7078         else
7079         {
7080                 if (rsurface.entityskeletaltransform3x4)
7081                 {
7082                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7083                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7084                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7085                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7086                 }
7087                 else
7088                 {
7089                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7090                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7091                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7092                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7093                 }
7094                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7095                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7096                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7097                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7098                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7099                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7100                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7101                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7102                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7103                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7104                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7105                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7106                 rsurface.modelgeneratedvertex = false;
7107         }
7108         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7109         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7110         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7111         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7112         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7113         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7114         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7115         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7116         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7117         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7118         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7119         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7120         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7121         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7122         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7123         rsurface.modelelement3i = model->surfmesh.data_element3i;
7124         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7125         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7126         rsurface.modelelement3s = model->surfmesh.data_element3s;
7127         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7128         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7129         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7130         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7131         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7132         rsurface.modelsurfaces = model->data_surfaces;
7133         rsurface.batchgeneratedvertex = false;
7134         rsurface.batchfirstvertex = 0;
7135         rsurface.batchnumvertices = 0;
7136         rsurface.batchfirsttriangle = 0;
7137         rsurface.batchnumtriangles = 0;
7138         rsurface.batchvertex3f  = NULL;
7139         rsurface.batchvertex3f_vertexbuffer = NULL;
7140         rsurface.batchvertex3f_bufferoffset = 0;
7141         rsurface.batchsvector3f = NULL;
7142         rsurface.batchsvector3f_vertexbuffer = NULL;
7143         rsurface.batchsvector3f_bufferoffset = 0;
7144         rsurface.batchtvector3f = NULL;
7145         rsurface.batchtvector3f_vertexbuffer = NULL;
7146         rsurface.batchtvector3f_bufferoffset = 0;
7147         rsurface.batchnormal3f  = NULL;
7148         rsurface.batchnormal3f_vertexbuffer = NULL;
7149         rsurface.batchnormal3f_bufferoffset = 0;
7150         rsurface.batchlightmapcolor4f = NULL;
7151         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7152         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7153         rsurface.batchtexcoordtexture2f = NULL;
7154         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7155         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7156         rsurface.batchtexcoordlightmap2f = NULL;
7157         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7158         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7159         rsurface.batchskeletalindex4ub = NULL;
7160         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7161         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7162         rsurface.batchskeletalweight4ub = NULL;
7163         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7164         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7165         rsurface.batchelement3i = NULL;
7166         rsurface.batchelement3i_indexbuffer = NULL;
7167         rsurface.batchelement3i_bufferoffset = 0;
7168         rsurface.batchelement3s = NULL;
7169         rsurface.batchelement3s_indexbuffer = NULL;
7170         rsurface.batchelement3s_bufferoffset = 0;
7171         rsurface.forcecurrenttextureupdate = false;
7172 }
7173
7174 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)
7175 {
7176         rsurface.entity = r_refdef.scene.worldentity;
7177         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7178                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7179                 // A better approach could be making this copy only once per frame.
7180                 static entity_render_t custom_entity;
7181                 int q;
7182                 custom_entity = *rsurface.entity;
7183                 for (q = 0; q < 3; ++q) {
7184                         float colormod = q == 0 ? r : q == 1 ? g : b;
7185                         custom_entity.render_fullbright[q] *= colormod;
7186                         custom_entity.render_modellight_ambient[q] *= colormod;
7187                         custom_entity.render_modellight_diffuse[q] *= colormod;
7188                         custom_entity.render_lightmap_ambient[q] *= colormod;
7189                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7190                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7191                 }
7192                 custom_entity.alpha *= a;
7193                 rsurface.entity = &custom_entity;
7194         }
7195         rsurface.skeleton = NULL;
7196         rsurface.ent_skinnum = 0;
7197         rsurface.ent_qwskin = -1;
7198         rsurface.ent_flags = entflags;
7199         rsurface.shadertime = r_refdef.scene.time - shadertime;
7200         rsurface.modelnumvertices = numvertices;
7201         rsurface.modelnumtriangles = numtriangles;
7202         rsurface.matrix = *matrix;
7203         rsurface.inversematrix = *inversematrix;
7204         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7205         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7206         R_EntityMatrix(&rsurface.matrix);
7207         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7208         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7209         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7210         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7211         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7212         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7213         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7214         rsurface.frameblend[0].lerp = 1;
7215         rsurface.ent_alttextures = false;
7216         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7217         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7218         rsurface.entityskeletaltransform3x4 = NULL;
7219         rsurface.entityskeletaltransform3x4buffer = NULL;
7220         rsurface.entityskeletaltransform3x4offset = 0;
7221         rsurface.entityskeletaltransform3x4size = 0;
7222         rsurface.entityskeletalnumtransforms = 0;
7223         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7224         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7225         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7226         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7227         if (wanttangents)
7228         {
7229                 rsurface.modelvertex3f = (float *)vertex3f;
7230                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7231                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7232                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7233         }
7234         else if (wantnormals)
7235         {
7236                 rsurface.modelvertex3f = (float *)vertex3f;
7237                 rsurface.modelsvector3f = NULL;
7238                 rsurface.modeltvector3f = NULL;
7239                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7240         }
7241         else
7242         {
7243                 rsurface.modelvertex3f = (float *)vertex3f;
7244                 rsurface.modelsvector3f = NULL;
7245                 rsurface.modeltvector3f = NULL;
7246                 rsurface.modelnormal3f = NULL;
7247         }
7248         rsurface.modelvertex3f_vertexbuffer = 0;
7249         rsurface.modelvertex3f_bufferoffset = 0;
7250         rsurface.modelsvector3f_vertexbuffer = 0;
7251         rsurface.modelsvector3f_bufferoffset = 0;
7252         rsurface.modeltvector3f_vertexbuffer = 0;
7253         rsurface.modeltvector3f_bufferoffset = 0;
7254         rsurface.modelnormal3f_vertexbuffer = 0;
7255         rsurface.modelnormal3f_bufferoffset = 0;
7256         rsurface.modelgeneratedvertex = true;
7257         rsurface.modellightmapcolor4f  = (float *)color4f;
7258         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7259         rsurface.modellightmapcolor4f_bufferoffset = 0;
7260         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7261         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7262         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7263         rsurface.modeltexcoordlightmap2f  = NULL;
7264         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7265         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7266         rsurface.modelskeletalindex4ub = NULL;
7267         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7268         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7269         rsurface.modelskeletalweight4ub = NULL;
7270         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7271         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7272         rsurface.modelelement3i = (int *)element3i;
7273         rsurface.modelelement3i_indexbuffer = NULL;
7274         rsurface.modelelement3i_bufferoffset = 0;
7275         rsurface.modelelement3s = (unsigned short *)element3s;
7276         rsurface.modelelement3s_indexbuffer = NULL;
7277         rsurface.modelelement3s_bufferoffset = 0;
7278         rsurface.modellightmapoffsets = NULL;
7279         rsurface.modelsurfaces = NULL;
7280         rsurface.batchgeneratedvertex = false;
7281         rsurface.batchfirstvertex = 0;
7282         rsurface.batchnumvertices = 0;
7283         rsurface.batchfirsttriangle = 0;
7284         rsurface.batchnumtriangles = 0;
7285         rsurface.batchvertex3f  = NULL;
7286         rsurface.batchvertex3f_vertexbuffer = NULL;
7287         rsurface.batchvertex3f_bufferoffset = 0;
7288         rsurface.batchsvector3f = NULL;
7289         rsurface.batchsvector3f_vertexbuffer = NULL;
7290         rsurface.batchsvector3f_bufferoffset = 0;
7291         rsurface.batchtvector3f = NULL;
7292         rsurface.batchtvector3f_vertexbuffer = NULL;
7293         rsurface.batchtvector3f_bufferoffset = 0;
7294         rsurface.batchnormal3f  = NULL;
7295         rsurface.batchnormal3f_vertexbuffer = NULL;
7296         rsurface.batchnormal3f_bufferoffset = 0;
7297         rsurface.batchlightmapcolor4f = NULL;
7298         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7299         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7300         rsurface.batchtexcoordtexture2f = NULL;
7301         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7302         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7303         rsurface.batchtexcoordlightmap2f = NULL;
7304         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7305         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7306         rsurface.batchskeletalindex4ub = NULL;
7307         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7308         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7309         rsurface.batchskeletalweight4ub = NULL;
7310         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7311         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7312         rsurface.batchelement3i = NULL;
7313         rsurface.batchelement3i_indexbuffer = NULL;
7314         rsurface.batchelement3i_bufferoffset = 0;
7315         rsurface.batchelement3s = NULL;
7316         rsurface.batchelement3s_indexbuffer = NULL;
7317         rsurface.batchelement3s_bufferoffset = 0;
7318         rsurface.forcecurrenttextureupdate = true;
7319
7320         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7321         {
7322                 if ((wantnormals || wanttangents) && !normal3f)
7323                 {
7324                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7325                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7326                 }
7327                 if (wanttangents && !svector3f)
7328                 {
7329                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7330                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7331                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7332                 }
7333         }
7334 }
7335
7336 float RSurf_FogPoint(const float *v)
7337 {
7338         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7339         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7340         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7341         float FogHeightFade = r_refdef.fogheightfade;
7342         float fogfrac;
7343         unsigned int fogmasktableindex;
7344         if (r_refdef.fogplaneviewabove)
7345                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7346         else
7347                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7348         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7349         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7350 }
7351
7352 float RSurf_FogVertex(const float *v)
7353 {
7354         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7355         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7356         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7357         float FogHeightFade = rsurface.fogheightfade;
7358         float fogfrac;
7359         unsigned int fogmasktableindex;
7360         if (r_refdef.fogplaneviewabove)
7361                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7362         else
7363                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7364         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7365         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7366 }
7367
7368 void RSurf_UploadBuffersForBatch(void)
7369 {
7370         // 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)
7371         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7372         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7373                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7374         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7375                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7376         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7377                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7378         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7379                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7380         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7381                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7382         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7383                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7384         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7385                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7386         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7387                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7388         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7389                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7390
7391         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7392                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7393         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7394                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7395
7396         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7397         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7398         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7399         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7400         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7401         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7402         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7403         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7404         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7405         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7406 }
7407
7408 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7409 {
7410         int i;
7411         for (i = 0;i < numelements;i++)
7412                 outelement3i[i] = inelement3i[i] + adjust;
7413 }
7414
7415 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7416 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7417 {
7418         int deformindex;
7419         int firsttriangle;
7420         int numtriangles;
7421         int firstvertex;
7422         int endvertex;
7423         int numvertices;
7424         int surfacefirsttriangle;
7425         int surfacenumtriangles;
7426         int surfacefirstvertex;
7427         int surfaceendvertex;
7428         int surfacenumvertices;
7429         int batchnumsurfaces = texturenumsurfaces;
7430         int batchnumvertices;
7431         int batchnumtriangles;
7432         int i, j;
7433         qbool gaps;
7434         qbool dynamicvertex;
7435         float amplitude;
7436         float animpos;
7437         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7438         float waveparms[4];
7439         unsigned char *ub;
7440         q3shaderinfo_deform_t *deform;
7441         const msurface_t *surface, *firstsurface;
7442         if (!texturenumsurfaces)
7443                 return;
7444         // find vertex range of this surface batch
7445         gaps = false;
7446         firstsurface = texturesurfacelist[0];
7447         firsttriangle = firstsurface->num_firsttriangle;
7448         batchnumvertices = 0;
7449         batchnumtriangles = 0;
7450         firstvertex = endvertex = firstsurface->num_firstvertex;
7451         for (i = 0;i < texturenumsurfaces;i++)
7452         {
7453                 surface = texturesurfacelist[i];
7454                 if (surface != firstsurface + i)
7455                         gaps = true;
7456                 surfacefirstvertex = surface->num_firstvertex;
7457                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7458                 surfacenumvertices = surface->num_vertices;
7459                 surfacenumtriangles = surface->num_triangles;
7460                 if (firstvertex > surfacefirstvertex)
7461                         firstvertex = surfacefirstvertex;
7462                 if (endvertex < surfaceendvertex)
7463                         endvertex = surfaceendvertex;
7464                 batchnumvertices += surfacenumvertices;
7465                 batchnumtriangles += surfacenumtriangles;
7466         }
7467
7468         r_refdef.stats[r_stat_batch_batches]++;
7469         if (gaps)
7470                 r_refdef.stats[r_stat_batch_withgaps]++;
7471         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7472         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7473         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7474
7475         // we now know the vertex range used, and if there are any gaps in it
7476         rsurface.batchfirstvertex = firstvertex;
7477         rsurface.batchnumvertices = endvertex - firstvertex;
7478         rsurface.batchfirsttriangle = firsttriangle;
7479         rsurface.batchnumtriangles = batchnumtriangles;
7480
7481         // check if any dynamic vertex processing must occur
7482         dynamicvertex = false;
7483
7484         // we must use vertexbuffers for rendering, we can upload vertex buffers
7485         // easily enough but if the basevertex is non-zero it becomes more
7486         // difficult, so force dynamicvertex path in that case - it's suboptimal
7487         // but the most optimal case is to have the geometry sources provide their
7488         // own anyway.
7489         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7490                 dynamicvertex = true;
7491
7492         // a cvar to force the dynamic vertex path to be taken, for debugging
7493         if (r_batch_debugdynamicvertexpath.integer)
7494         {
7495                 if (!dynamicvertex)
7496                 {
7497                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7498                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7499                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7500                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7501                 }
7502                 dynamicvertex = true;
7503         }
7504
7505         // if there is a chance of animated vertex colors, it's a dynamic batch
7506         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7507         {
7508                 if (!dynamicvertex)
7509                 {
7510                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7511                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7512                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7513                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7514                 }
7515                 dynamicvertex = true;
7516         }
7517
7518         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7519         {
7520                 switch (deform->deform)
7521                 {
7522                 default:
7523                 case Q3DEFORM_PROJECTIONSHADOW:
7524                 case Q3DEFORM_TEXT0:
7525                 case Q3DEFORM_TEXT1:
7526                 case Q3DEFORM_TEXT2:
7527                 case Q3DEFORM_TEXT3:
7528                 case Q3DEFORM_TEXT4:
7529                 case Q3DEFORM_TEXT5:
7530                 case Q3DEFORM_TEXT6:
7531                 case Q3DEFORM_TEXT7:
7532                 case Q3DEFORM_NONE:
7533                         break;
7534                 case Q3DEFORM_AUTOSPRITE:
7535                         if (!dynamicvertex)
7536                         {
7537                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7538                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7539                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7540                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7541                         }
7542                         dynamicvertex = true;
7543                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7544                         break;
7545                 case Q3DEFORM_AUTOSPRITE2:
7546                         if (!dynamicvertex)
7547                         {
7548                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7549                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7550                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7551                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7552                         }
7553                         dynamicvertex = true;
7554                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7555                         break;
7556                 case Q3DEFORM_NORMAL:
7557                         if (!dynamicvertex)
7558                         {
7559                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7560                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7561                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7562                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7563                         }
7564                         dynamicvertex = true;
7565                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7566                         break;
7567                 case Q3DEFORM_WAVE:
7568                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7569                                 break; // if wavefunc is a nop, ignore this transform
7570                         if (!dynamicvertex)
7571                         {
7572                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7573                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7574                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7575                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7576                         }
7577                         dynamicvertex = true;
7578                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7579                         break;
7580                 case Q3DEFORM_BULGE:
7581                         if (!dynamicvertex)
7582                         {
7583                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7584                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7585                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7586                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7587                         }
7588                         dynamicvertex = true;
7589                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7590                         break;
7591                 case Q3DEFORM_MOVE:
7592                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7593                                 break; // if wavefunc is a nop, ignore this transform
7594                         if (!dynamicvertex)
7595                         {
7596                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7597                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7598                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7599                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7600                         }
7601                         dynamicvertex = true;
7602                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7603                         break;
7604                 }
7605         }
7606         if (rsurface.texture->materialshaderpass)
7607         {
7608                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7609                 {
7610                 default:
7611                 case Q3TCGEN_TEXTURE:
7612                         break;
7613                 case Q3TCGEN_LIGHTMAP:
7614                         if (!dynamicvertex)
7615                         {
7616                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7617                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7618                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7619                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7620                         }
7621                         dynamicvertex = true;
7622                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7623                         break;
7624                 case Q3TCGEN_VECTOR:
7625                         if (!dynamicvertex)
7626                         {
7627                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7628                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7629                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7630                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7631                         }
7632                         dynamicvertex = true;
7633                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7634                         break;
7635                 case Q3TCGEN_ENVIRONMENT:
7636                         if (!dynamicvertex)
7637                         {
7638                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7639                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7640                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7641                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7642                         }
7643                         dynamicvertex = true;
7644                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7645                         break;
7646                 }
7647                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7648                 {
7649                         if (!dynamicvertex)
7650                         {
7651                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7652                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7653                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7654                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7655                         }
7656                         dynamicvertex = true;
7657                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7658                 }
7659         }
7660
7661         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7662         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7663         // we ensure this by treating the vertex batch as dynamic...
7664         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7665         {
7666                 if (!dynamicvertex)
7667                 {
7668                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7669                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7670                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7671                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7672                 }
7673                 dynamicvertex = true;
7674         }
7675
7676         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7677         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7678                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7679
7680         rsurface.batchvertex3f = rsurface.modelvertex3f;
7681         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7682         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7683         rsurface.batchsvector3f = rsurface.modelsvector3f;
7684         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7685         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7686         rsurface.batchtvector3f = rsurface.modeltvector3f;
7687         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7688         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7689         rsurface.batchnormal3f = rsurface.modelnormal3f;
7690         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7691         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7692         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7693         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7694         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7695         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7696         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7697         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7698         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7699         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7700         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7701         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7702         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7703         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7704         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7705         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7706         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7707         rsurface.batchelement3i = rsurface.modelelement3i;
7708         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7709         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7710         rsurface.batchelement3s = rsurface.modelelement3s;
7711         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7712         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7713         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7714         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7715         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7716         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7717         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7718
7719         // if any dynamic vertex processing has to occur in software, we copy the
7720         // entire surface list together before processing to rebase the vertices
7721         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7722         //
7723         // if any gaps exist and we do not have a static vertex buffer, we have to
7724         // copy the surface list together to avoid wasting upload bandwidth on the
7725         // vertices in the gaps.
7726         //
7727         // if gaps exist and we have a static vertex buffer, we can choose whether
7728         // to combine the index buffer ranges into one dynamic index buffer or
7729         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7730         //
7731         // in many cases the batch is reduced to one draw call.
7732
7733         rsurface.batchmultidraw = false;
7734         rsurface.batchmultidrawnumsurfaces = 0;
7735         rsurface.batchmultidrawsurfacelist = NULL;
7736
7737         if (!dynamicvertex)
7738         {
7739                 // static vertex data, just set pointers...
7740                 rsurface.batchgeneratedvertex = false;
7741                 // if there are gaps, we want to build a combined index buffer,
7742                 // otherwise use the original static buffer with an appropriate offset
7743                 if (gaps)
7744                 {
7745                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7746                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7747                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7748                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7749                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7750                         {
7751                                 rsurface.batchmultidraw = true;
7752                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7753                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7754                                 return;
7755                         }
7756                         // build a new triangle elements array for this batch
7757                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7758                         rsurface.batchfirsttriangle = 0;
7759                         numtriangles = 0;
7760                         for (i = 0;i < texturenumsurfaces;i++)
7761                         {
7762                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7763                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7764                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7765                                 numtriangles += surfacenumtriangles;
7766                         }
7767                         rsurface.batchelement3i_indexbuffer = NULL;
7768                         rsurface.batchelement3i_bufferoffset = 0;
7769                         rsurface.batchelement3s = NULL;
7770                         rsurface.batchelement3s_indexbuffer = NULL;
7771                         rsurface.batchelement3s_bufferoffset = 0;
7772                         if (endvertex <= 65536)
7773                         {
7774                                 // make a 16bit (unsigned short) index array if possible
7775                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7776                                 for (i = 0;i < numtriangles*3;i++)
7777                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7778                         }
7779                 }
7780                 else
7781                 {
7782                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7783                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7784                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7785                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7786                 }
7787                 return;
7788         }
7789
7790         // something needs software processing, do it for real...
7791         // we only directly handle separate array data in this case and then
7792         // generate interleaved data if needed...
7793         rsurface.batchgeneratedvertex = true;
7794         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7795         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7796         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7797         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7798
7799         // now copy the vertex data into a combined array and make an index array
7800         // (this is what Quake3 does all the time)
7801         // we also apply any skeletal animation here that would have been done in
7802         // the vertex shader, because most of the dynamic vertex animation cases
7803         // need actual vertex positions and normals
7804         //if (dynamicvertex)
7805         {
7806                 rsurface.batchvertex3f = NULL;
7807                 rsurface.batchvertex3f_vertexbuffer = NULL;
7808                 rsurface.batchvertex3f_bufferoffset = 0;
7809                 rsurface.batchsvector3f = NULL;
7810                 rsurface.batchsvector3f_vertexbuffer = NULL;
7811                 rsurface.batchsvector3f_bufferoffset = 0;
7812                 rsurface.batchtvector3f = NULL;
7813                 rsurface.batchtvector3f_vertexbuffer = NULL;
7814                 rsurface.batchtvector3f_bufferoffset = 0;
7815                 rsurface.batchnormal3f = NULL;
7816                 rsurface.batchnormal3f_vertexbuffer = NULL;
7817                 rsurface.batchnormal3f_bufferoffset = 0;
7818                 rsurface.batchlightmapcolor4f = NULL;
7819                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7820                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7821                 rsurface.batchtexcoordtexture2f = NULL;
7822                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7823                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7824                 rsurface.batchtexcoordlightmap2f = NULL;
7825                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7826                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7827                 rsurface.batchskeletalindex4ub = NULL;
7828                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7829                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7830                 rsurface.batchskeletalweight4ub = NULL;
7831                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7832                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7833                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7834                 rsurface.batchelement3i_indexbuffer = NULL;
7835                 rsurface.batchelement3i_bufferoffset = 0;
7836                 rsurface.batchelement3s = NULL;
7837                 rsurface.batchelement3s_indexbuffer = NULL;
7838                 rsurface.batchelement3s_bufferoffset = 0;
7839                 rsurface.batchskeletaltransform3x4buffer = NULL;
7840                 rsurface.batchskeletaltransform3x4offset = 0;
7841                 rsurface.batchskeletaltransform3x4size = 0;
7842                 // we'll only be setting up certain arrays as needed
7843                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7844                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7845                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7846                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7847                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7848                 {
7849                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7850                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7851                 }
7852                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7853                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7854                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7855                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7856                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7857                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7858                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7859                 {
7860                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7861                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7862                 }
7863                 numvertices = 0;
7864                 numtriangles = 0;
7865                 for (i = 0;i < texturenumsurfaces;i++)
7866                 {
7867                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7868                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7869                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7870                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7871                         // copy only the data requested
7872                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7873                         {
7874                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7875                                 {
7876                                         if (rsurface.batchvertex3f)
7877                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7878                                         else
7879                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7880                                 }
7881                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7882                                 {
7883                                         if (rsurface.modelnormal3f)
7884                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7885                                         else
7886                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7887                                 }
7888                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7889                                 {
7890                                         if (rsurface.modelsvector3f)
7891                                         {
7892                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7893                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7894                                         }
7895                                         else
7896                                         {
7897                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7898                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7899                                         }
7900                                 }
7901                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7902                                 {
7903                                         if (rsurface.modellightmapcolor4f)
7904                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7905                                         else
7906                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7907                                 }
7908                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7909                                 {
7910                                         if (rsurface.modeltexcoordtexture2f)
7911                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7912                                         else
7913                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7914                                 }
7915                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7916                                 {
7917                                         if (rsurface.modeltexcoordlightmap2f)
7918                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7919                                         else
7920                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7921                                 }
7922                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7923                                 {
7924                                         if (rsurface.modelskeletalindex4ub)
7925                                         {
7926                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7927                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7928                                         }
7929                                         else
7930                                         {
7931                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7932                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7933                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7934                                                 for (j = 0;j < surfacenumvertices;j++)
7935                                                         ub[j*4] = 255;
7936                                         }
7937                                 }
7938                         }
7939                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7940                         numvertices += surfacenumvertices;
7941                         numtriangles += surfacenumtriangles;
7942                 }
7943
7944                 // generate a 16bit index array as well if possible
7945                 // (in general, dynamic batches fit)
7946                 if (numvertices <= 65536)
7947                 {
7948                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7949                         for (i = 0;i < numtriangles*3;i++)
7950                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7951                 }
7952
7953                 // since we've copied everything, the batch now starts at 0
7954                 rsurface.batchfirstvertex = 0;
7955                 rsurface.batchnumvertices = batchnumvertices;
7956                 rsurface.batchfirsttriangle = 0;
7957                 rsurface.batchnumtriangles = batchnumtriangles;
7958         }
7959
7960         // apply skeletal animation that would have been done in the vertex shader
7961         if (rsurface.batchskeletaltransform3x4)
7962         {
7963                 const unsigned char *si;
7964                 const unsigned char *sw;
7965                 const float *t[4];
7966                 const float *b = rsurface.batchskeletaltransform3x4;
7967                 float *vp, *vs, *vt, *vn;
7968                 float w[4];
7969                 float m[3][4], n[3][4];
7970                 float tp[3], ts[3], tt[3], tn[3];
7971                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7972                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7973                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7974                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7975                 si = rsurface.batchskeletalindex4ub;
7976                 sw = rsurface.batchskeletalweight4ub;
7977                 vp = rsurface.batchvertex3f;
7978                 vs = rsurface.batchsvector3f;
7979                 vt = rsurface.batchtvector3f;
7980                 vn = rsurface.batchnormal3f;
7981                 memset(m[0], 0, sizeof(m));
7982                 memset(n[0], 0, sizeof(n));
7983                 for (i = 0;i < batchnumvertices;i++)
7984                 {
7985                         t[0] = b + si[0]*12;
7986                         if (sw[0] == 255)
7987                         {
7988                                 // common case - only one matrix
7989                                 m[0][0] = t[0][ 0];
7990                                 m[0][1] = t[0][ 1];
7991                                 m[0][2] = t[0][ 2];
7992                                 m[0][3] = t[0][ 3];
7993                                 m[1][0] = t[0][ 4];
7994                                 m[1][1] = t[0][ 5];
7995                                 m[1][2] = t[0][ 6];
7996                                 m[1][3] = t[0][ 7];
7997                                 m[2][0] = t[0][ 8];
7998                                 m[2][1] = t[0][ 9];
7999                                 m[2][2] = t[0][10];
8000                                 m[2][3] = t[0][11];
8001                         }
8002                         else if (sw[2] + sw[3])
8003                         {
8004                                 // blend 4 matrices
8005                                 t[1] = b + si[1]*12;
8006                                 t[2] = b + si[2]*12;
8007                                 t[3] = b + si[3]*12;
8008                                 w[0] = sw[0] * (1.0f / 255.0f);
8009                                 w[1] = sw[1] * (1.0f / 255.0f);
8010                                 w[2] = sw[2] * (1.0f / 255.0f);
8011                                 w[3] = sw[3] * (1.0f / 255.0f);
8012                                 // blend the matrices
8013                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8014                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8015                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8016                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8017                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8018                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8019                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8020                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8021                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8022                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8023                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8024                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8025                         }
8026                         else
8027                         {
8028                                 // blend 2 matrices
8029                                 t[1] = b + si[1]*12;
8030                                 w[0] = sw[0] * (1.0f / 255.0f);
8031                                 w[1] = sw[1] * (1.0f / 255.0f);
8032                                 // blend the matrices
8033                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8034                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8035                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8036                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8037                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8038                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8039                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8040                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8041                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8042                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8043                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8044                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8045                         }
8046                         si += 4;
8047                         sw += 4;
8048                         // modify the vertex
8049                         VectorCopy(vp, tp);
8050                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8051                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8052                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8053                         vp += 3;
8054                         if (vn)
8055                         {
8056                                 // the normal transformation matrix is a set of cross products...
8057                                 CrossProduct(m[1], m[2], n[0]);
8058                                 CrossProduct(m[2], m[0], n[1]);
8059                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8060                                 VectorCopy(vn, tn);
8061                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8062                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8063                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8064                                 VectorNormalize(vn);
8065                                 vn += 3;
8066                                 if (vs)
8067                                 {
8068                                         VectorCopy(vs, ts);
8069                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8070                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8071                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8072                                         VectorNormalize(vs);
8073                                         vs += 3;
8074                                         VectorCopy(vt, tt);
8075                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8076                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8077                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8078                                         VectorNormalize(vt);
8079                                         vt += 3;
8080                                 }
8081                         }
8082                 }
8083                 rsurface.batchskeletaltransform3x4 = NULL;
8084                 rsurface.batchskeletalnumtransforms = 0;
8085         }
8086
8087         // q1bsp surfaces rendered in vertex color mode have to have colors
8088         // calculated based on lightstyles
8089         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8090         {
8091                 // generate color arrays for the surfaces in this list
8092                 int c[4];
8093                 int scale;
8094                 int size3;
8095                 const int *offsets;
8096                 const unsigned char *lm;
8097                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8098                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8099                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8100                 numvertices = 0;
8101                 for (i = 0;i < texturenumsurfaces;i++)
8102                 {
8103                         surface = texturesurfacelist[i];
8104                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8105                         surfacenumvertices = surface->num_vertices;
8106                         if (surface->lightmapinfo->samples)
8107                         {
8108                                 for (j = 0;j < surfacenumvertices;j++)
8109                                 {
8110                                         lm = surface->lightmapinfo->samples + offsets[j];
8111                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8112                                         VectorScale(lm, scale, c);
8113                                         if (surface->lightmapinfo->styles[1] != 255)
8114                                         {
8115                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8116                                                 lm += size3;
8117                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8118                                                 VectorMA(c, scale, lm, c);
8119                                                 if (surface->lightmapinfo->styles[2] != 255)
8120                                                 {
8121                                                         lm += size3;
8122                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8123                                                         VectorMA(c, scale, lm, c);
8124                                                         if (surface->lightmapinfo->styles[3] != 255)
8125                                                         {
8126                                                                 lm += size3;
8127                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8128                                                                 VectorMA(c, scale, lm, c);
8129                                                         }
8130                                                 }
8131                                         }
8132                                         c[0] >>= 7;
8133                                         c[1] >>= 7;
8134                                         c[2] >>= 7;
8135                                         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);
8136                                         numvertices++;
8137                                 }
8138                         }
8139                         else
8140                         {
8141                                 for (j = 0;j < surfacenumvertices;j++)
8142                                 {
8143                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8144                                         numvertices++;
8145                                 }
8146                         }
8147                 }
8148         }
8149
8150         // if vertices are deformed (sprite flares and things in maps, possibly
8151         // water waves, bulges and other deformations), modify the copied vertices
8152         // in place
8153         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8154         {
8155                 float scale;
8156                 switch (deform->deform)
8157                 {
8158                 default:
8159                 case Q3DEFORM_PROJECTIONSHADOW:
8160                 case Q3DEFORM_TEXT0:
8161                 case Q3DEFORM_TEXT1:
8162                 case Q3DEFORM_TEXT2:
8163                 case Q3DEFORM_TEXT3:
8164                 case Q3DEFORM_TEXT4:
8165                 case Q3DEFORM_TEXT5:
8166                 case Q3DEFORM_TEXT6:
8167                 case Q3DEFORM_TEXT7:
8168                 case Q3DEFORM_NONE:
8169                         break;
8170                 case Q3DEFORM_AUTOSPRITE:
8171                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8172                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8173                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8174                         VectorNormalize(newforward);
8175                         VectorNormalize(newright);
8176                         VectorNormalize(newup);
8177 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8178 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8179 //                      rsurface.batchvertex3f_bufferoffset = 0;
8180 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8181 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8182 //                      rsurface.batchsvector3f_bufferoffset = 0;
8183 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8184 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8185 //                      rsurface.batchtvector3f_bufferoffset = 0;
8186 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8187 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8188 //                      rsurface.batchnormal3f_bufferoffset = 0;
8189                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8190                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8191                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8192                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8193                                 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);
8194                         // a single autosprite surface can contain multiple sprites...
8195                         for (j = 0;j < batchnumvertices - 3;j += 4)
8196                         {
8197                                 VectorClear(center);
8198                                 for (i = 0;i < 4;i++)
8199                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8200                                 VectorScale(center, 0.25f, center);
8201                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8202                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8203                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8204                                 for (i = 0;i < 4;i++)
8205                                 {
8206                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8207                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8208                                 }
8209                         }
8210                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8211                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8212                         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);
8213                         break;
8214                 case Q3DEFORM_AUTOSPRITE2:
8215                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8216                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8217                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8218                         VectorNormalize(newforward);
8219                         VectorNormalize(newright);
8220                         VectorNormalize(newup);
8221 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8222 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8223 //                      rsurface.batchvertex3f_bufferoffset = 0;
8224                         {
8225                                 const float *v1, *v2;
8226                                 vec3_t start, end;
8227                                 float f, l;
8228                                 struct
8229                                 {
8230                                         float length2;
8231                                         const float *v1;
8232                                         const float *v2;
8233                                 }
8234                                 shortest[2];
8235                                 memset(shortest, 0, sizeof(shortest));
8236                                 // a single autosprite surface can contain multiple sprites...
8237                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8238                                 {
8239                                         VectorClear(center);
8240                                         for (i = 0;i < 4;i++)
8241                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8242                                         VectorScale(center, 0.25f, center);
8243                                         // find the two shortest edges, then use them to define the
8244                                         // axis vectors for rotating around the central axis
8245                                         for (i = 0;i < 6;i++)
8246                                         {
8247                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8248                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8249                                                 l = VectorDistance2(v1, v2);
8250                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8251                                                 if (v1[2] != v2[2])
8252                                                         l += (1.0f / 1024.0f);
8253                                                 if (shortest[0].length2 > l || i == 0)
8254                                                 {
8255                                                         shortest[1] = shortest[0];
8256                                                         shortest[0].length2 = l;
8257                                                         shortest[0].v1 = v1;
8258                                                         shortest[0].v2 = v2;
8259                                                 }
8260                                                 else if (shortest[1].length2 > l || i == 1)
8261                                                 {
8262                                                         shortest[1].length2 = l;
8263                                                         shortest[1].v1 = v1;
8264                                                         shortest[1].v2 = v2;
8265                                                 }
8266                                         }
8267                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8268                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8269                                         // this calculates the right vector from the shortest edge
8270                                         // and the up vector from the edge midpoints
8271                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8272                                         VectorNormalize(right);
8273                                         VectorSubtract(end, start, up);
8274                                         VectorNormalize(up);
8275                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8276                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8277                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8278                                         VectorNegate(forward, forward);
8279                                         VectorReflect(forward, 0, up, forward);
8280                                         VectorNormalize(forward);
8281                                         CrossProduct(up, forward, newright);
8282                                         VectorNormalize(newright);
8283                                         // rotate the quad around the up axis vector, this is made
8284                                         // especially easy by the fact we know the quad is flat,
8285                                         // so we only have to subtract the center position and
8286                                         // measure distance along the right vector, and then
8287                                         // multiply that by the newright vector and add back the
8288                                         // center position
8289                                         // we also need to subtract the old position to undo the
8290                                         // displacement from the center, which we do with a
8291                                         // DotProduct, the subtraction/addition of center is also
8292                                         // optimized into DotProducts here
8293                                         l = DotProduct(right, center);
8294                                         for (i = 0;i < 4;i++)
8295                                         {
8296                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8297                                                 f = DotProduct(right, v1) - l;
8298                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8299                                         }
8300                                 }
8301                         }
8302                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8303                         {
8304 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8305 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8306 //                              rsurface.batchnormal3f_bufferoffset = 0;
8307                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8308                         }
8309                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8310                         {
8311 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8312 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8313 //                              rsurface.batchsvector3f_bufferoffset = 0;
8314 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8315 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8316 //                              rsurface.batchtvector3f_bufferoffset = 0;
8317                                 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);
8318                         }
8319                         break;
8320                 case Q3DEFORM_NORMAL:
8321                         // deform the normals to make reflections wavey
8322                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8323                         rsurface.batchnormal3f_vertexbuffer = NULL;
8324                         rsurface.batchnormal3f_bufferoffset = 0;
8325                         for (j = 0;j < batchnumvertices;j++)
8326                         {
8327                                 float vertex[3];
8328                                 float *normal = rsurface.batchnormal3f + 3*j;
8329                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8330                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8331                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8332                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8333                                 VectorNormalize(normal);
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_WAVE:
8347                         // deform vertex array to make wavey water and flags and such
8348                         waveparms[0] = deform->waveparms[0];
8349                         waveparms[1] = deform->waveparms[1];
8350                         waveparms[2] = deform->waveparms[2];
8351                         waveparms[3] = deform->waveparms[3];
8352                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8353                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8354                         // this is how a divisor of vertex influence on deformation
8355                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8356                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8357 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8358 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8359 //                      rsurface.batchvertex3f_bufferoffset = 0;
8360 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8361 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8362 //                      rsurface.batchnormal3f_bufferoffset = 0;
8363                         for (j = 0;j < batchnumvertices;j++)
8364                         {
8365                                 // if the wavefunc depends on time, evaluate it per-vertex
8366                                 if (waveparms[3])
8367                                 {
8368                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8369                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8370                                 }
8371                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8372                         }
8373                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8374                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8375                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8376                         {
8377 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8378 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8379 //                              rsurface.batchsvector3f_bufferoffset = 0;
8380 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8381 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8382 //                              rsurface.batchtvector3f_bufferoffset = 0;
8383                                 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);
8384                         }
8385                         break;
8386                 case Q3DEFORM_BULGE:
8387                         // deform vertex array to make the surface have moving bulges
8388 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8389 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8390 //                      rsurface.batchvertex3f_bufferoffset = 0;
8391 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8392 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8393 //                      rsurface.batchnormal3f_bufferoffset = 0;
8394                         for (j = 0;j < batchnumvertices;j++)
8395                         {
8396                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
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_MOVE:
8413                         // deform vertex array
8414                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8415                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8416                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8417                         VectorScale(deform->parms, scale, waveparms);
8418 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8419 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8420 //                      rsurface.batchvertex3f_bufferoffset = 0;
8421                         for (j = 0;j < batchnumvertices;j++)
8422                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8423                         break;
8424                 }
8425         }
8426
8427         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8428         {
8429         // generate texcoords based on the chosen texcoord source
8430                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8431                 {
8432                 default:
8433                 case Q3TCGEN_TEXTURE:
8434                         break;
8435                 case Q3TCGEN_LIGHTMAP:
8436         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8437         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8438         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8439                         if (rsurface.batchtexcoordlightmap2f)
8440                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8441                         break;
8442                 case Q3TCGEN_VECTOR:
8443         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8444         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8445         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8446                         for (j = 0;j < batchnumvertices;j++)
8447                         {
8448                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8449                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8450                         }
8451                         break;
8452                 case Q3TCGEN_ENVIRONMENT:
8453                         // make environment reflections using a spheremap
8454                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8455                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8456                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8457                         for (j = 0;j < batchnumvertices;j++)
8458                         {
8459                                 // identical to Q3A's method, but executed in worldspace so
8460                                 // carried models can be shiny too
8461
8462                                 float viewer[3], d, reflected[3], worldreflected[3];
8463
8464                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8465                                 // VectorNormalize(viewer);
8466
8467                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8468
8469                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8470                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8471                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8472                                 // note: this is proportinal to viewer, so we can normalize later
8473
8474                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8475                                 VectorNormalize(worldreflected);
8476
8477                                 // note: this sphere map only uses world x and z!
8478                                 // so positive and negative y will LOOK THE SAME.
8479                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8480                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8481                         }
8482                         break;
8483                 }
8484                 // the only tcmod that needs software vertex processing is turbulent, so
8485                 // check for it here and apply the changes if needed
8486                 // and we only support that as the first one
8487                 // (handling a mixture of turbulent and other tcmods would be problematic
8488                 //  without punting it entirely to a software path)
8489                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8490                 {
8491                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8492                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8493         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8494         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8495         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8496                         for (j = 0;j < batchnumvertices;j++)
8497                         {
8498                                 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);
8499                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8500                         }
8501                 }
8502         }
8503 }
8504
8505 void RSurf_DrawBatch(void)
8506 {
8507         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8508         // through the pipeline, killing it earlier in the pipeline would have
8509         // per-surface overhead rather than per-batch overhead, so it's best to
8510         // reject it here, before it hits glDraw.
8511         if (rsurface.batchnumtriangles == 0)
8512                 return;
8513 #if 0
8514         // batch debugging code
8515         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8516         {
8517                 int i;
8518                 int j;
8519                 int c;
8520                 const int *e;
8521                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8522                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8523                 {
8524                         c = e[i];
8525                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8526                         {
8527                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8528                                 {
8529                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8530                                                 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);
8531                                         break;
8532                                 }
8533                         }
8534                 }
8535         }
8536 #endif
8537         if (rsurface.batchmultidraw)
8538         {
8539                 // issue multiple draws rather than copying index data
8540                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8541                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8542                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8543                 for (i = 0;i < numsurfaces;)
8544                 {
8545                         // combine consecutive surfaces as one draw
8546                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8547                                 if (surfacelist[j] != surfacelist[k] + 1)
8548                                         break;
8549                         firstvertex = surfacelist[i]->num_firstvertex;
8550                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8551                         firsttriangle = surfacelist[i]->num_firsttriangle;
8552                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8553                         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);
8554                         i = j;
8555                 }
8556         }
8557         else
8558         {
8559                 // there is only one consecutive run of index data (may have been combined)
8560                 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);
8561         }
8562 }
8563
8564 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8565 {
8566         // pick the closest matching water plane
8567         int planeindex, vertexindex, bestplaneindex = -1;
8568         float d, bestd;
8569         vec3_t vert;
8570         const float *v;
8571         r_waterstate_waterplane_t *p;
8572         qbool prepared = false;
8573         bestd = 0;
8574         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8575         {
8576                 if(p->camera_entity != rsurface.texture->camera_entity)
8577                         continue;
8578                 d = 0;
8579                 if(!prepared)
8580                 {
8581                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8582                         prepared = true;
8583                         if(rsurface.batchnumvertices == 0)
8584                                 break;
8585                 }
8586                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8587                 {
8588                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8589                         d += fabs(PlaneDiff(vert, &p->plane));
8590                 }
8591                 if (bestd > d || bestplaneindex < 0)
8592                 {
8593                         bestd = d;
8594                         bestplaneindex = planeindex;
8595                 }
8596         }
8597         return bestplaneindex;
8598         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8599         // this situation though, as it might be better to render single larger
8600         // batches with useless stuff (backface culled for example) than to
8601         // render multiple smaller batches
8602 }
8603
8604 void RSurf_SetupDepthAndCulling(bool ui)
8605 {
8606         // submodels are biased to avoid z-fighting with world surfaces that they
8607         // may be exactly overlapping (avoids z-fighting artifacts on certain
8608         // doors and things in Quake maps)
8609         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8610         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8611         GL_DepthTest(!ui && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8612         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8613 }
8614
8615 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8616 {
8617         int j;
8618         const float *v;
8619         float p[3], mins[3], maxs[3];
8620         int scissor[4];
8621         // transparent sky would be ridiculous
8622         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8623                 return;
8624         R_SetupShader_Generic_NoTexture(false, false);
8625         skyrenderlater = true;
8626         RSurf_SetupDepthAndCulling(false);
8627         GL_DepthMask(true);
8628
8629         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8630         if (r_sky_scissor.integer)
8631         {
8632                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8633                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8634                 {
8635                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8636                         if (j > 0)
8637                         {
8638                                 if (mins[0] > p[0]) mins[0] = p[0];
8639                                 if (mins[1] > p[1]) mins[1] = p[1];
8640                                 if (mins[2] > p[2]) mins[2] = p[2];
8641                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8642                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8643                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8644                         }
8645                         else
8646                         {
8647                                 VectorCopy(p, mins);
8648                                 VectorCopy(p, maxs);
8649                         }
8650                 }
8651                 if (!R_ScissorForBBox(mins, maxs, scissor))
8652                 {
8653                         if (skyscissor[2])
8654                         {
8655                                 if (skyscissor[0] > scissor[0])
8656                                 {
8657                                         skyscissor[2] += skyscissor[0] - scissor[0];
8658                                         skyscissor[0] = scissor[0];
8659                                 }
8660                                 if (skyscissor[1] > scissor[1])
8661                                 {
8662                                         skyscissor[3] += skyscissor[1] - scissor[1];
8663                                         skyscissor[1] = scissor[1];
8664                                 }
8665                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8666                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8667                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8668                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8669                         }
8670                         else
8671                                 Vector4Copy(scissor, skyscissor);
8672                 }
8673         }
8674
8675         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8676         // skymasking on them, and Quake3 never did sky masking (unlike
8677         // software Quake and software Quake2), so disable the sky masking
8678         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8679         // and skymasking also looks very bad when noclipping outside the
8680         // level, so don't use it then either.
8681         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)
8682         {
8683                 R_Mesh_ResetTextureState();
8684                 if (skyrendermasked)
8685                 {
8686                         R_SetupShader_DepthOrShadow(false, false, false);
8687                         // depth-only (masking)
8688                         GL_ColorMask(0, 0, 0, 0);
8689                         // just to make sure that braindead drivers don't draw
8690                         // anything despite that colormask...
8691                         GL_BlendFunc(GL_ZERO, GL_ONE);
8692                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8693                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8694                 }
8695                 else
8696                 {
8697                         R_SetupShader_Generic_NoTexture(false, false);
8698                         // fog sky
8699                         GL_BlendFunc(GL_ONE, GL_ZERO);
8700                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8701                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8702                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8703                 }
8704                 RSurf_DrawBatch();
8705                 if (skyrendermasked)
8706                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8707         }
8708         R_Mesh_ResetTextureState();
8709         GL_Color(1, 1, 1, 1);
8710 }
8711
8712 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8713 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8714 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8715 {
8716         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8717                 return;
8718         if (prepass)
8719         {
8720                 // render screenspace normalmap to texture
8721                 GL_DepthMask(true);
8722                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8723                 RSurf_DrawBatch();
8724                 return;
8725         }
8726
8727         // bind lightmap texture
8728
8729         // water/refraction/reflection/camera surfaces have to be handled specially
8730         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8731         {
8732                 int start, end, startplaneindex;
8733                 for (start = 0;start < texturenumsurfaces;start = end)
8734                 {
8735                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8736                         if(startplaneindex < 0)
8737                         {
8738                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8739                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8740                                 end = start + 1;
8741                                 continue;
8742                         }
8743                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8744                                 ;
8745                         // now that we have a batch using the same planeindex, render it
8746                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8747                         {
8748                                 // render water or distortion background
8749                                 GL_DepthMask(true);
8750                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8751                                 RSurf_DrawBatch();
8752                                 // blend surface on top
8753                                 GL_DepthMask(false);
8754                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8755                                 RSurf_DrawBatch();
8756                         }
8757                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8758                         {
8759                                 // render surface with reflection texture as input
8760                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8761                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8762                                 RSurf_DrawBatch();
8763                         }
8764                 }
8765                 return;
8766         }
8767
8768         // render surface batch normally
8769         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8770         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8771         RSurf_DrawBatch();
8772 }
8773
8774 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8775 {
8776         int vi;
8777         int j;
8778         int texturesurfaceindex;
8779         int k;
8780         const msurface_t *surface;
8781         float surfacecolor4f[4];
8782         float c[4];
8783         texture_t *t = rsurface.texture;
8784
8785 //      R_Mesh_ResetTextureState();
8786         R_SetupShader_Generic_NoTexture(false, false);
8787
8788         GL_BlendFunc(GL_ONE, GL_ZERO);
8789         GL_DepthMask(writedepth);
8790
8791         switch (r_showsurfaces.integer)
8792         {
8793                 case 1:
8794                 default:
8795                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8796                         vi = 0;
8797                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8798                         {
8799                                 surface = texturesurfacelist[texturesurfaceindex];
8800                                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8801                                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8802                                 for (j = 0;j < surface->num_vertices;j++)
8803                                 {
8804                                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8805                                         vi++;
8806                                 }
8807                         }
8808                         break;
8809                 case 3:
8810                         if(t && t->currentskinframe)
8811                         {
8812                                 Vector4Copy(t->currentskinframe->avgcolor, c);
8813                                 c[3] *= t->currentalpha;
8814                         }
8815                         else
8816                         {
8817                                 Vector4Set(c, 1, 0, 1, 1);
8818                         }
8819                         if (t && (t->pantstexture || t->shirttexture))
8820                         {
8821                                 VectorMAM(0.7, t->render_colormap_pants, 0.3, t->render_colormap_shirt, c);
8822                         }
8823                         VectorScale(c, 2 * r_refdef.view.colorscale, c);
8824                         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
8825                                 c[3] *= r_wateralpha.value;
8826                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8827                         vi = 0;
8828                         if (rsurface.modellightmapcolor4f)
8829                         {
8830                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8831                                 {
8832                                         surface = texturesurfacelist[texturesurfaceindex];
8833                                         for (j = 0;j < surface->num_vertices;j++)
8834                                         {
8835                                                 float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
8836                                                 Vector4Multiply(ptr, c, ptr);
8837                                                 vi++;
8838                                         }
8839                                 }
8840                         }
8841                         else
8842                         {
8843                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8844                                 {
8845                                         surface = texturesurfacelist[texturesurfaceindex];
8846                                         for (j = 0;j < surface->num_vertices;j++)
8847                                         {
8848                                                 float *ptr = rsurface.batchlightmapcolor4f + 4 * vi;
8849                                                 Vector4Copy(c, ptr);
8850                                                 vi++;
8851                                         }
8852                                 }
8853                         }
8854                         break;
8855         }
8856         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8857         RSurf_DrawBatch();
8858 }
8859
8860 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8861 {
8862         CHECKGLERROR
8863         RSurf_SetupDepthAndCulling(ui);
8864         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8865         {
8866                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8867                 return;
8868         }
8869         switch (vid.renderpath)
8870         {
8871         case RENDERPATH_GL32:
8872         case RENDERPATH_GLES2:
8873                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8874                 break;
8875         }
8876         CHECKGLERROR
8877 }
8878
8879 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8880 {
8881         int i, j;
8882         int texturenumsurfaces, endsurface;
8883         texture_t *texture;
8884         const msurface_t *surface;
8885         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8886
8887         RSurf_ActiveModelEntity(ent, true, true, false);
8888
8889         if (r_transparentdepthmasking.integer)
8890         {
8891                 qbool setup = false;
8892                 for (i = 0;i < numsurfaces;i = j)
8893                 {
8894                         j = i + 1;
8895                         surface = rsurface.modelsurfaces + surfacelist[i];
8896                         texture = surface->texture;
8897                         rsurface.texture = R_GetCurrentTexture(texture);
8898                         rsurface.lightmaptexture = NULL;
8899                         rsurface.deluxemaptexture = NULL;
8900                         rsurface.uselightmaptexture = false;
8901                         // scan ahead until we find a different texture
8902                         endsurface = min(i + 1024, numsurfaces);
8903                         texturenumsurfaces = 0;
8904                         texturesurfacelist[texturenumsurfaces++] = surface;
8905                         for (;j < endsurface;j++)
8906                         {
8907                                 surface = rsurface.modelsurfaces + surfacelist[j];
8908                                 if (texture != surface->texture)
8909                                         break;
8910                                 texturesurfacelist[texturenumsurfaces++] = surface;
8911                         }
8912                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8913                                 continue;
8914                         // render the range of surfaces as depth
8915                         if (!setup)
8916                         {
8917                                 setup = true;
8918                                 GL_ColorMask(0,0,0,0);
8919                                 GL_Color(1,1,1,1);
8920                                 GL_DepthTest(true);
8921                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8922                                 GL_DepthMask(true);
8923 //                              R_Mesh_ResetTextureState();
8924                         }
8925                         RSurf_SetupDepthAndCulling(false);
8926                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8927                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8928                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8929                         RSurf_DrawBatch();
8930                 }
8931                 if (setup)
8932                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8933         }
8934
8935         for (i = 0;i < numsurfaces;i = j)
8936         {
8937                 j = i + 1;
8938                 surface = rsurface.modelsurfaces + surfacelist[i];
8939                 texture = surface->texture;
8940                 rsurface.texture = R_GetCurrentTexture(texture);
8941                 // scan ahead until we find a different texture
8942                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8943                 texturenumsurfaces = 0;
8944                 texturesurfacelist[texturenumsurfaces++] = surface;
8945                         rsurface.lightmaptexture = surface->lightmaptexture;
8946                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8947                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8948                         for (;j < endsurface;j++)
8949                         {
8950                                 surface = rsurface.modelsurfaces + surfacelist[j];
8951                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8952                                         break;
8953                                 texturesurfacelist[texturenumsurfaces++] = surface;
8954                         }
8955                 // render the range of surfaces
8956                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8957         }
8958         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8959 }
8960
8961 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8962 {
8963         // transparent surfaces get pushed off into the transparent queue
8964         int surfacelistindex;
8965         const msurface_t *surface;
8966         vec3_t tempcenter, center;
8967         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8968         {
8969                 surface = texturesurfacelist[surfacelistindex];
8970                 if (r_transparent_sortsurfacesbynearest.integer)
8971                 {
8972                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8973                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8974                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8975                 }
8976                 else
8977                 {
8978                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8979                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8980                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8981                 }
8982                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8983                 if (rsurface.entity->transparent_offset) // transparent offset
8984                 {
8985                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8986                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8987                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8988                 }
8989                 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);
8990         }
8991 }
8992
8993 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8994 {
8995         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8996                 return;
8997         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8998                 return;
8999         RSurf_SetupDepthAndCulling(false);
9000         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9001         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9002         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9003         RSurf_DrawBatch();
9004 }
9005
9006 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9007 {
9008         CHECKGLERROR
9009         if (ui)
9010                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9011         else if (depthonly)
9012                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9013         else if (prepass)
9014         {
9015                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9016                         return;
9017                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9018                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9019                 else
9020                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9021         }
9022         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9023                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9024         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9025                 return;
9026         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9027         {
9028                 // in the deferred case, transparent surfaces were queued during prepass
9029                 if (!r_shadow_usingdeferredprepass)
9030                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9031         }
9032         else
9033         {
9034                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9035                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9036         }
9037         CHECKGLERROR
9038 }
9039
9040 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
9041 {
9042         int i, j;
9043         texture_t *texture;
9044         R_FrameData_SetMark();
9045         // break the surface list down into batches by texture and use of lightmapping
9046         for (i = 0;i < numsurfaces;i = j)
9047         {
9048                 j = i + 1;
9049                 // texture is the base texture pointer, rsurface.texture is the
9050                 // current frame/skin the texture is directing us to use (for example
9051                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9052                 // use skin 1 instead)
9053                 texture = surfacelist[i]->texture;
9054                 rsurface.texture = R_GetCurrentTexture(texture);
9055                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9056                 {
9057                         // if this texture is not the kind we want, skip ahead to the next one
9058                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9059                                 ;
9060                         continue;
9061                 }
9062                 if(depthonly || prepass)
9063                 {
9064                         rsurface.lightmaptexture = NULL;
9065                         rsurface.deluxemaptexture = NULL;
9066                         rsurface.uselightmaptexture = false;
9067                         // simply scan ahead until we find a different texture or lightmap state
9068                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9069                                 ;
9070                 }
9071                 else
9072                 {
9073                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9074                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9075                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9076                         // simply scan ahead until we find a different texture or lightmap state
9077                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9078                                 ;
9079                 }
9080                 // render the range of surfaces
9081                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9082         }
9083         R_FrameData_ReturnToMark();
9084 }
9085
9086 float locboxvertex3f[6*4*3] =
9087 {
9088         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9089         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9090         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9091         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9092         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9093         1,0,0, 0,0,0, 0,1,0, 1,1,0
9094 };
9095
9096 unsigned short locboxelements[6*2*3] =
9097 {
9098          0, 1, 2, 0, 2, 3,
9099          4, 5, 6, 4, 6, 7,
9100          8, 9,10, 8,10,11,
9101         12,13,14, 12,14,15,
9102         16,17,18, 16,18,19,
9103         20,21,22, 20,22,23
9104 };
9105
9106 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9107 {
9108         int i, j;
9109         cl_locnode_t *loc = (cl_locnode_t *)ent;
9110         vec3_t mins, size;
9111         float vertex3f[6*4*3];
9112         CHECKGLERROR
9113         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9114         GL_DepthMask(false);
9115         GL_DepthRange(0, 1);
9116         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9117         GL_DepthTest(true);
9118         GL_CullFace(GL_NONE);
9119         R_EntityMatrix(&identitymatrix);
9120
9121 //      R_Mesh_ResetTextureState();
9122
9123         i = surfacelist[0];
9124         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9125                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9126                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9127                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9128
9129         if (VectorCompare(loc->mins, loc->maxs))
9130         {
9131                 VectorSet(size, 2, 2, 2);
9132                 VectorMA(loc->mins, -0.5f, size, mins);
9133         }
9134         else
9135         {
9136                 VectorCopy(loc->mins, mins);
9137                 VectorSubtract(loc->maxs, loc->mins, size);
9138         }
9139
9140         for (i = 0;i < 6*4*3;)
9141                 for (j = 0;j < 3;j++, i++)
9142                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9143
9144         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9145         R_SetupShader_Generic_NoTexture(false, false);
9146         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9147 }
9148
9149 void R_DrawLocs(void)
9150 {
9151         int index;
9152         cl_locnode_t *loc, *nearestloc;
9153         vec3_t center;
9154         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9155         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9156         {
9157                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9158                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9159         }
9160 }
9161
9162 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9163 {
9164         if (decalsystem->decals)
9165                 Mem_Free(decalsystem->decals);
9166         memset(decalsystem, 0, sizeof(*decalsystem));
9167 }
9168
9169 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)
9170 {
9171         tridecal_t *decal;
9172         tridecal_t *decals;
9173         int i;
9174
9175         // expand or initialize the system
9176         if (decalsystem->maxdecals <= decalsystem->numdecals)
9177         {
9178                 decalsystem_t old = *decalsystem;
9179                 qbool useshortelements;
9180                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9181                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9182                 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)));
9183                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9184                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9185                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9186                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9187                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9188                 if (decalsystem->numdecals)
9189                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9190                 if (old.decals)
9191                         Mem_Free(old.decals);
9192                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9193                         decalsystem->element3i[i] = i;
9194                 if (useshortelements)
9195                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9196                                 decalsystem->element3s[i] = i;
9197         }
9198
9199         // grab a decal and search for another free slot for the next one
9200         decals = decalsystem->decals;
9201         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9202         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9203                 ;
9204         decalsystem->freedecal = i;
9205         if (decalsystem->numdecals <= i)
9206                 decalsystem->numdecals = i + 1;
9207
9208         // initialize the decal
9209         decal->lived = 0;
9210         decal->triangleindex = triangleindex;
9211         decal->surfaceindex = surfaceindex;
9212         decal->decalsequence = decalsequence;
9213         decal->color4f[0][0] = c0[0];
9214         decal->color4f[0][1] = c0[1];
9215         decal->color4f[0][2] = c0[2];
9216         decal->color4f[0][3] = 1;
9217         decal->color4f[1][0] = c1[0];
9218         decal->color4f[1][1] = c1[1];
9219         decal->color4f[1][2] = c1[2];
9220         decal->color4f[1][3] = 1;
9221         decal->color4f[2][0] = c2[0];
9222         decal->color4f[2][1] = c2[1];
9223         decal->color4f[2][2] = c2[2];
9224         decal->color4f[2][3] = 1;
9225         decal->vertex3f[0][0] = v0[0];
9226         decal->vertex3f[0][1] = v0[1];
9227         decal->vertex3f[0][2] = v0[2];
9228         decal->vertex3f[1][0] = v1[0];
9229         decal->vertex3f[1][1] = v1[1];
9230         decal->vertex3f[1][2] = v1[2];
9231         decal->vertex3f[2][0] = v2[0];
9232         decal->vertex3f[2][1] = v2[1];
9233         decal->vertex3f[2][2] = v2[2];
9234         decal->texcoord2f[0][0] = t0[0];
9235         decal->texcoord2f[0][1] = t0[1];
9236         decal->texcoord2f[1][0] = t1[0];
9237         decal->texcoord2f[1][1] = t1[1];
9238         decal->texcoord2f[2][0] = t2[0];
9239         decal->texcoord2f[2][1] = t2[1];
9240         TriangleNormal(v0, v1, v2, decal->plane);
9241         VectorNormalize(decal->plane);
9242         decal->plane[3] = DotProduct(v0, decal->plane);
9243 }
9244
9245 extern cvar_t cl_decals_bias;
9246 extern cvar_t cl_decals_models;
9247 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9248 // baseparms, parms, temps
9249 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)
9250 {
9251         int cornerindex;
9252         int index;
9253         float v[9][3];
9254         const float *vertex3f;
9255         const float *normal3f;
9256         int numpoints;
9257         float points[2][9][3];
9258         float temp[3];
9259         float tc[9][2];
9260         float f;
9261         float c[9][4];
9262         const int *e;
9263
9264         e = rsurface.modelelement3i + 3*triangleindex;
9265
9266         vertex3f = rsurface.modelvertex3f;
9267         normal3f = rsurface.modelnormal3f;
9268
9269         if (normal3f)
9270         {
9271                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9272                 {
9273                         index = 3*e[cornerindex];
9274                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9275                 }
9276         }
9277         else
9278         {
9279                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9280                 {
9281                         index = 3*e[cornerindex];
9282                         VectorCopy(vertex3f + index, v[cornerindex]);
9283                 }
9284         }
9285
9286         // cull backfaces
9287         //TriangleNormal(v[0], v[1], v[2], normal);
9288         //if (DotProduct(normal, localnormal) < 0.0f)
9289         //      continue;
9290         // clip by each of the box planes formed from the projection matrix
9291         // if anything survives, we emit the decal
9292         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]);
9293         if (numpoints < 3)
9294                 return;
9295         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]);
9296         if (numpoints < 3)
9297                 return;
9298         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]);
9299         if (numpoints < 3)
9300                 return;
9301         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]);
9302         if (numpoints < 3)
9303                 return;
9304         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]);
9305         if (numpoints < 3)
9306                 return;
9307         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]);
9308         if (numpoints < 3)
9309                 return;
9310         // some part of the triangle survived, so we have to accept it...
9311         if (dynamic)
9312         {
9313                 // dynamic always uses the original triangle
9314                 numpoints = 3;
9315                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9316                 {
9317                         index = 3*e[cornerindex];
9318                         VectorCopy(vertex3f + index, v[cornerindex]);
9319                 }
9320         }
9321         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9322         {
9323                 // convert vertex positions to texcoords
9324                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9325                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9326                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9327                 // calculate distance fade from the projection origin
9328                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9329                 f = bound(0.0f, f, 1.0f);
9330                 c[cornerindex][0] = r * f;
9331                 c[cornerindex][1] = g * f;
9332                 c[cornerindex][2] = b * f;
9333                 c[cornerindex][3] = 1.0f;
9334                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9335         }
9336         if (dynamic)
9337                 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);
9338         else
9339                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9340                         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);
9341 }
9342 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)
9343 {
9344         matrix4x4_t projection;
9345         decalsystem_t *decalsystem;
9346         qbool dynamic;
9347         model_t *model;
9348         const msurface_t *surface;
9349         const msurface_t *surfaces;
9350         const texture_t *texture;
9351         int numtriangles;
9352         int surfaceindex;
9353         int triangleindex;
9354         float localorigin[3];
9355         float localnormal[3];
9356         float localmins[3];
9357         float localmaxs[3];
9358         float localsize;
9359         //float normal[3];
9360         float planes[6][4];
9361         float angles[3];
9362         bih_t *bih;
9363         int bih_triangles_count;
9364         int bih_triangles[256];
9365         int bih_surfaces[256];
9366
9367         decalsystem = &ent->decalsystem;
9368         model = ent->model;
9369         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9370         {
9371                 R_DecalSystem_Reset(&ent->decalsystem);
9372                 return;
9373         }
9374
9375         if (!model->brush.data_leafs && !cl_decals_models.integer)
9376         {
9377                 if (decalsystem->model)
9378                         R_DecalSystem_Reset(decalsystem);
9379                 return;
9380         }
9381
9382         if (decalsystem->model != model)
9383                 R_DecalSystem_Reset(decalsystem);
9384         decalsystem->model = model;
9385
9386         RSurf_ActiveModelEntity(ent, true, false, false);
9387
9388         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9389         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9390         VectorNormalize(localnormal);
9391         localsize = worldsize*rsurface.inversematrixscale;
9392         localmins[0] = localorigin[0] - localsize;
9393         localmins[1] = localorigin[1] - localsize;
9394         localmins[2] = localorigin[2] - localsize;
9395         localmaxs[0] = localorigin[0] + localsize;
9396         localmaxs[1] = localorigin[1] + localsize;
9397         localmaxs[2] = localorigin[2] + localsize;
9398
9399         //VectorCopy(localnormal, planes[4]);
9400         //VectorVectors(planes[4], planes[2], planes[0]);
9401         AnglesFromVectors(angles, localnormal, NULL, false);
9402         AngleVectors(angles, planes[0], planes[2], planes[4]);
9403         VectorNegate(planes[0], planes[1]);
9404         VectorNegate(planes[2], planes[3]);
9405         VectorNegate(planes[4], planes[5]);
9406         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9407         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9408         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9409         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9410         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9411         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9412
9413 #if 1
9414 // works
9415 {
9416         matrix4x4_t forwardprojection;
9417         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9418         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9419 }
9420 #else
9421 // broken
9422 {
9423         float projectionvector[4][3];
9424         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9425         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9426         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9427         projectionvector[0][0] = planes[0][0] * ilocalsize;
9428         projectionvector[0][1] = planes[1][0] * ilocalsize;
9429         projectionvector[0][2] = planes[2][0] * ilocalsize;
9430         projectionvector[1][0] = planes[0][1] * ilocalsize;
9431         projectionvector[1][1] = planes[1][1] * ilocalsize;
9432         projectionvector[1][2] = planes[2][1] * ilocalsize;
9433         projectionvector[2][0] = planes[0][2] * ilocalsize;
9434         projectionvector[2][1] = planes[1][2] * ilocalsize;
9435         projectionvector[2][2] = planes[2][2] * ilocalsize;
9436         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9437         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9438         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9439         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9440 }
9441 #endif
9442
9443         dynamic = model->surfmesh.isanimated;
9444         surfaces = model->data_surfaces;
9445
9446         bih = NULL;
9447         bih_triangles_count = -1;
9448         if(!dynamic)
9449         {
9450                 if(model->render_bih.numleafs)
9451                         bih = &model->render_bih;
9452                 else if(model->collision_bih.numleafs)
9453                         bih = &model->collision_bih;
9454         }
9455         if(bih)
9456                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9457         if(bih_triangles_count == 0)
9458                 return;
9459         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9460                 return;
9461         if(bih_triangles_count > 0)
9462         {
9463                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9464                 {
9465                         surfaceindex = bih_surfaces[triangleindex];
9466                         surface = surfaces + surfaceindex;
9467                         texture = surface->texture;
9468                         if (!texture)
9469                                 continue;
9470                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9471                                 continue;
9472                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9473                                 continue;
9474                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9475                 }
9476         }
9477         else
9478         {
9479                 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
9480                 {
9481                         surface = surfaces + surfaceindex;
9482                         // check cull box first because it rejects more than any other check
9483                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9484                                 continue;
9485                         // skip transparent surfaces
9486                         texture = surface->texture;
9487                         if (!texture)
9488                                 continue;
9489                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9490                                 continue;
9491                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9492                                 continue;
9493                         numtriangles = surface->num_triangles;
9494                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9495                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9496                 }
9497         }
9498 }
9499
9500 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9501 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)
9502 {
9503         int renderentityindex;
9504         float worldmins[3];
9505         float worldmaxs[3];
9506         entity_render_t *ent;
9507
9508         worldmins[0] = worldorigin[0] - worldsize;
9509         worldmins[1] = worldorigin[1] - worldsize;
9510         worldmins[2] = worldorigin[2] - worldsize;
9511         worldmaxs[0] = worldorigin[0] + worldsize;
9512         worldmaxs[1] = worldorigin[1] + worldsize;
9513         worldmaxs[2] = worldorigin[2] + worldsize;
9514
9515         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9516
9517         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9518         {
9519                 ent = r_refdef.scene.entities[renderentityindex];
9520                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9521                         continue;
9522
9523                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9524         }
9525 }
9526
9527 typedef struct r_decalsystem_splatqueue_s
9528 {
9529         vec3_t worldorigin;
9530         vec3_t worldnormal;
9531         float color[4];
9532         float tcrange[4];
9533         float worldsize;
9534         unsigned int decalsequence;
9535 }
9536 r_decalsystem_splatqueue_t;
9537
9538 int r_decalsystem_numqueued = 0;
9539 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9540
9541 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)
9542 {
9543         r_decalsystem_splatqueue_t *queue;
9544
9545         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9546                 return;
9547
9548         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9549         VectorCopy(worldorigin, queue->worldorigin);
9550         VectorCopy(worldnormal, queue->worldnormal);
9551         Vector4Set(queue->color, r, g, b, a);
9552         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9553         queue->worldsize = worldsize;
9554         queue->decalsequence = cl.decalsequence++;
9555 }
9556
9557 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9558 {
9559         int i;
9560         r_decalsystem_splatqueue_t *queue;
9561
9562         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9563                 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);
9564         r_decalsystem_numqueued = 0;
9565 }
9566
9567 extern cvar_t cl_decals_max;
9568 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9569 {
9570         int i;
9571         decalsystem_t *decalsystem = &ent->decalsystem;
9572         int numdecals;
9573         unsigned int killsequence;
9574         tridecal_t *decal;
9575         float frametime;
9576         float lifetime;
9577
9578         if (!decalsystem->numdecals)
9579                 return;
9580
9581         if (r_showsurfaces.integer)
9582                 return;
9583
9584         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9585         {
9586                 R_DecalSystem_Reset(decalsystem);
9587                 return;
9588         }
9589
9590         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9591         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9592
9593         if (decalsystem->lastupdatetime)
9594                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9595         else
9596                 frametime = 0;
9597         decalsystem->lastupdatetime = r_refdef.scene.time;
9598         numdecals = decalsystem->numdecals;
9599
9600         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9601         {
9602                 if (decal->color4f[0][3])
9603                 {
9604                         decal->lived += frametime;
9605                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9606                         {
9607                                 memset(decal, 0, sizeof(*decal));
9608                                 if (decalsystem->freedecal > i)
9609                                         decalsystem->freedecal = i;
9610                         }
9611                 }
9612         }
9613         decal = decalsystem->decals;
9614         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9615                 numdecals--;
9616
9617         // collapse the array by shuffling the tail decals into the gaps
9618         for (;;)
9619         {
9620                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9621                         decalsystem->freedecal++;
9622                 if (decalsystem->freedecal == numdecals)
9623                         break;
9624                 decal[decalsystem->freedecal] = decal[--numdecals];
9625         }
9626
9627         decalsystem->numdecals = numdecals;
9628
9629         if (numdecals <= 0)
9630         {
9631                 // if there are no decals left, reset decalsystem
9632                 R_DecalSystem_Reset(decalsystem);
9633         }
9634 }
9635
9636 extern skinframe_t *decalskinframe;
9637 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9638 {
9639         int i;
9640         decalsystem_t *decalsystem = &ent->decalsystem;
9641         int numdecals;
9642         tridecal_t *decal;
9643         float faderate;
9644         float alpha;
9645         float *v3f;
9646         float *c4f;
9647         float *t2f;
9648         const int *e;
9649         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9650         int numtris = 0;
9651
9652         numdecals = decalsystem->numdecals;
9653         if (!numdecals)
9654                 return;
9655
9656         if (r_showsurfaces.integer)
9657                 return;
9658
9659         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9660         {
9661                 R_DecalSystem_Reset(decalsystem);
9662                 return;
9663         }
9664
9665         // if the model is static it doesn't matter what value we give for
9666         // wantnormals and wanttangents, so this logic uses only rules applicable
9667         // to a model, knowing that they are meaningless otherwise
9668         RSurf_ActiveModelEntity(ent, false, false, false);
9669
9670         decalsystem->lastupdatetime = r_refdef.scene.time;
9671
9672         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9673
9674         // update vertex positions for animated models
9675         v3f = decalsystem->vertex3f;
9676         c4f = decalsystem->color4f;
9677         t2f = decalsystem->texcoord2f;
9678         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9679         {
9680                 if (!decal->color4f[0][3])
9681                         continue;
9682
9683                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9684                         continue;
9685
9686                 // skip backfaces
9687                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9688                         continue;
9689
9690                 // update color values for fading decals
9691                 if (decal->lived >= cl_decals_time.value)
9692                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9693                 else
9694                         alpha = 1.0f;
9695
9696                 c4f[ 0] = decal->color4f[0][0] * alpha;
9697                 c4f[ 1] = decal->color4f[0][1] * alpha;
9698                 c4f[ 2] = decal->color4f[0][2] * alpha;
9699                 c4f[ 3] = 1;
9700                 c4f[ 4] = decal->color4f[1][0] * alpha;
9701                 c4f[ 5] = decal->color4f[1][1] * alpha;
9702                 c4f[ 6] = decal->color4f[1][2] * alpha;
9703                 c4f[ 7] = 1;
9704                 c4f[ 8] = decal->color4f[2][0] * alpha;
9705                 c4f[ 9] = decal->color4f[2][1] * alpha;
9706                 c4f[10] = decal->color4f[2][2] * alpha;
9707                 c4f[11] = 1;
9708
9709                 t2f[0] = decal->texcoord2f[0][0];
9710                 t2f[1] = decal->texcoord2f[0][1];
9711                 t2f[2] = decal->texcoord2f[1][0];
9712                 t2f[3] = decal->texcoord2f[1][1];
9713                 t2f[4] = decal->texcoord2f[2][0];
9714                 t2f[5] = decal->texcoord2f[2][1];
9715
9716                 // update vertex positions for animated models
9717                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9718                 {
9719                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9720                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9721                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9722                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9723                 }
9724                 else
9725                 {
9726                         VectorCopy(decal->vertex3f[0], v3f);
9727                         VectorCopy(decal->vertex3f[1], v3f + 3);
9728                         VectorCopy(decal->vertex3f[2], v3f + 6);
9729                 }
9730
9731                 if (r_refdef.fogenabled)
9732                 {
9733                         alpha = RSurf_FogVertex(v3f);
9734                         VectorScale(c4f, alpha, c4f);
9735                         alpha = RSurf_FogVertex(v3f + 3);
9736                         VectorScale(c4f + 4, alpha, c4f + 4);
9737                         alpha = RSurf_FogVertex(v3f + 6);
9738                         VectorScale(c4f + 8, alpha, c4f + 8);
9739                 }
9740
9741                 v3f += 9;
9742                 c4f += 12;
9743                 t2f += 6;
9744                 numtris++;
9745         }
9746
9747         if (numtris > 0)
9748         {
9749                 r_refdef.stats[r_stat_drawndecals] += numtris;
9750
9751                 // now render the decals all at once
9752                 // (this assumes they all use one particle font texture!)
9753                 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);
9754 //              R_Mesh_ResetTextureState();
9755                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9756                 GL_DepthMask(false);
9757                 GL_DepthRange(0, 1);
9758                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9759                 GL_DepthTest(true);
9760                 GL_CullFace(GL_NONE);
9761                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9762                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9763                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9764         }
9765 }
9766
9767 static void R_DrawModelDecals(void)
9768 {
9769         int i, numdecals;
9770
9771         // fade faster when there are too many decals
9772         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9773         for (i = 0;i < r_refdef.scene.numentities;i++)
9774                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9775
9776         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9777         for (i = 0;i < r_refdef.scene.numentities;i++)
9778                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9779                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9780
9781         R_DecalSystem_ApplySplatEntitiesQueue();
9782
9783         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9784         for (i = 0;i < r_refdef.scene.numentities;i++)
9785                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9786
9787         r_refdef.stats[r_stat_totaldecals] += numdecals;
9788
9789         if (r_showsurfaces.integer || !r_drawdecals.integer)
9790                 return;
9791
9792         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9793
9794         for (i = 0;i < r_refdef.scene.numentities;i++)
9795         {
9796                 if (!r_refdef.viewcache.entityvisible[i])
9797                         continue;
9798                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9799                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9800         }
9801 }
9802
9803 static void R_DrawDebugModel(void)
9804 {
9805         entity_render_t *ent = rsurface.entity;
9806         int j, flagsmask;
9807         const msurface_t *surface;
9808         model_t *model = ent->model;
9809
9810         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9811                 return;
9812
9813         if (r_showoverdraw.value > 0)
9814         {
9815                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9816                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9817                 R_SetupShader_Generic_NoTexture(false, false);
9818                 GL_DepthTest(false);
9819                 GL_DepthMask(false);
9820                 GL_DepthRange(0, 1);
9821                 GL_BlendFunc(GL_ONE, GL_ONE);
9822                 for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
9823                 {
9824                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9825                                 continue;
9826                         surface = model->data_surfaces + j;
9827                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9828                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9829                         {
9830                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9831                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9832                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9833                                         GL_Color(c, 0, 0, 1.0f);
9834                                 else if (ent == r_refdef.scene.worldentity)
9835                                         GL_Color(c, c, c, 1.0f);
9836                                 else
9837                                         GL_Color(0, c, 0, 1.0f);
9838                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9839                                 RSurf_DrawBatch();
9840                         }
9841                 }
9842                 rsurface.texture = NULL;
9843         }
9844
9845         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9846
9847 //      R_Mesh_ResetTextureState();
9848         R_SetupShader_Generic_NoTexture(false, false);
9849         GL_DepthRange(0, 1);
9850         GL_DepthTest(!r_showdisabledepthtest.integer);
9851         GL_DepthMask(false);
9852         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9853
9854         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9855         {
9856                 int triangleindex;
9857                 int bihleafindex;
9858                 qbool cullbox = false;
9859                 const q3mbrush_t *brush;
9860                 const bih_t *bih = &model->collision_bih;
9861                 const bih_leaf_t *bihleaf;
9862                 float vertex3f[3][3];
9863                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9864                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9865                 {
9866                         if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs))
9867                                 continue;
9868                         switch (bihleaf->type)
9869                         {
9870                         case BIH_BRUSH:
9871                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9872                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9873                                 {
9874                                         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);
9875                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9876                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9877                                 }
9878                                 break;
9879                         case BIH_COLLISIONTRIANGLE:
9880                                 triangleindex = bihleaf->itemindex;
9881                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9882                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9883                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9884                                 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);
9885                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9886                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9887                                 break;
9888                         case BIH_RENDERTRIANGLE:
9889                                 triangleindex = bihleaf->itemindex;
9890                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9891                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9892                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9893                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
9894                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9895                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9896                                 break;
9897                         }
9898                 }
9899         }
9900
9901         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9902
9903 #ifndef USE_GLES2
9904         if (r_showtris.value > 0 && qglPolygonMode)
9905         {
9906                 if (r_showdisabledepthtest.integer)
9907                 {
9908                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9909                         GL_DepthMask(false);
9910                 }
9911                 else
9912                 {
9913                         GL_BlendFunc(GL_ONE, GL_ZERO);
9914                         GL_DepthMask(true);
9915                 }
9916                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9917                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9918                 {
9919                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9920                                 continue;
9921                         surface = model->data_surfaces + j;
9922                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9923                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9924                         {
9925                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9926                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9927                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9928                                 else if (ent == r_refdef.scene.worldentity)
9929                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9930                                 else
9931                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9932                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9933                                 RSurf_DrawBatch();
9934                         }
9935                 }
9936                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9937                 rsurface.texture = NULL;
9938         }
9939
9940 # if 0
9941         // FIXME!  implement r_shownormals with just triangles
9942         if (r_shownormals.value != 0 && qglBegin)
9943         {
9944                 int l, k;
9945                 vec3_t v;
9946                 if (r_showdisabledepthtest.integer)
9947                 {
9948                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9949                         GL_DepthMask(false);
9950                 }
9951                 else
9952                 {
9953                         GL_BlendFunc(GL_ONE, GL_ZERO);
9954                         GL_DepthMask(true);
9955                 }
9956                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9957                 {
9958                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9959                                 continue;
9960                         surface = model->data_surfaces + j;
9961                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9962                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9963                         {
9964                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9965                                 qglBegin(GL_LINES);
9966                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9967                                 {
9968                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9969                                         {
9970                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9971                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9972                                                 qglVertex3f(v[0], v[1], v[2]);
9973                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9974                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9975                                                 qglVertex3f(v[0], v[1], v[2]);
9976                                         }
9977                                 }
9978                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9979                                 {
9980                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9981                                         {
9982                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9983                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9984                                                 qglVertex3f(v[0], v[1], v[2]);
9985                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9986                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9987                                                 qglVertex3f(v[0], v[1], v[2]);
9988                                         }
9989                                 }
9990                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9991                                 {
9992                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9993                                         {
9994                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9995                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9996                                                 qglVertex3f(v[0], v[1], v[2]);
9997                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9998                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9999                                                 qglVertex3f(v[0], v[1], v[2]);
10000                                         }
10001                                 }
10002                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10003                                 {
10004                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10005                                         {
10006                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10007                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10008                                                 qglVertex3f(v[0], v[1], v[2]);
10009                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10010                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10011                                                 qglVertex3f(v[0], v[1], v[2]);
10012                                         }
10013                                 }
10014                                 qglEnd();
10015                                 CHECKGLERROR
10016                         }
10017                 }
10018                 rsurface.texture = NULL;
10019         }
10020 # endif
10021 #endif
10022 }
10023
10024 int r_maxsurfacelist = 0;
10025 const msurface_t **r_surfacelist = NULL;
10026 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
10027 {
10028         int i, j, flagsmask;
10029         model_t *model = ent->model;
10030         msurface_t *surfaces;
10031         unsigned char *update;
10032         int numsurfacelist = 0;
10033         if (model == NULL)
10034                 return;
10035
10036         if (r_maxsurfacelist < model->num_surfaces)
10037         {
10038                 r_maxsurfacelist = model->num_surfaces;
10039                 if (r_surfacelist)
10040                         Mem_Free((msurface_t **)r_surfacelist);
10041                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10042         }
10043
10044         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10045                 RSurf_ActiveModelEntity(ent, false, false, false);
10046         else if (prepass)
10047                 RSurf_ActiveModelEntity(ent, true, true, true);
10048         else if (depthonly)
10049                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10050         else
10051                 RSurf_ActiveModelEntity(ent, true, true, false);
10052
10053         surfaces = model->data_surfaces;
10054         update = model->brushq1.lightmapupdateflags;
10055
10056         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10057
10058         if (debug)
10059         {
10060                 R_DrawDebugModel();
10061                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10062                 return;
10063         }
10064
10065         // check if this is an empty model
10066         if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
10067                 return;
10068
10069         rsurface.lightmaptexture = NULL;
10070         rsurface.deluxemaptexture = NULL;
10071         rsurface.uselightmaptexture = false;
10072         rsurface.texture = NULL;
10073         rsurface.rtlight = NULL;
10074         numsurfacelist = 0;
10075
10076         // add visible surfaces to draw list
10077         if (ent == r_refdef.scene.worldentity)
10078         {
10079                 // for the world entity, check surfacevisible
10080                 for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
10081                 {
10082                         j = model->modelsurfaces_sorted[i];
10083                         if (r_refdef.viewcache.world_surfacevisible[j])
10084                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10085                 }
10086
10087                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10088                 if (!numsurfacelist)
10089                 {
10090                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10091                         return;
10092                 }
10093         }
10094         else if (ui)
10095         {
10096                 // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
10097                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10098                         r_surfacelist[numsurfacelist++] = surfaces + i;
10099         }
10100         else
10101         {
10102                 // add all surfaces
10103                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10104                         r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
10105         }
10106
10107         /*
10108          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10109          * using style chains because most styles do not change on most frames, and most
10110          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10111          * break this rule and animate most surfaces.
10112          */
10113         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10114         {
10115                 model_brush_lightstyleinfo_t *style;
10116
10117                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10118                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10119                 {
10120                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10121                         {
10122                                 int* list = style->surfacelist;
10123                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10124                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10125                                 for (j = 0; j < style->numsurfaces; j++)
10126                                         update[list[j]] = true;
10127                         }
10128                 }
10129                 // Now check if update flags are set on any surfaces that are visible
10130                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10131                 {
10132                         /*
10133                          * We can do less frequent texture uploads (approximately 10hz for animated
10134                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10135                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10136                          * use model->num_surfaces, not nummodelsurfaces.
10137                          */
10138                         for (i = 0; i < model->num_surfaces;i++)
10139                                 if (update[i])
10140                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10141                 }
10142                 else
10143                 {
10144                         for (i = 0; i < numsurfacelist; i++)
10145                                 if (update[r_surfacelist[i] - surfaces])
10146                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10147                 }
10148         }
10149
10150         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10151
10152         // add to stats if desired
10153         if (r_speeds.integer && !skysurfaces && !depthonly)
10154         {
10155                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10156                 for (j = 0;j < numsurfacelist;j++)
10157                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10158         }
10159
10160         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10161 }
10162
10163 void R_DebugLine(vec3_t start, vec3_t end)
10164 {
10165         model_t *mod = CL_Mesh_UI();
10166         msurface_t *surf;
10167         int e0, e1, e2, e3;
10168         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10169         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10170         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10171         vec4_t w[2], s[2];
10172
10173         // transform to screen coords first
10174         Vector4Set(w[0], start[0], start[1], start[2], 1);
10175         Vector4Set(w[1], end[0], end[1], end[2], 1);
10176         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10177         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10178         x1 = s[0][0] * vid_conwidth.value / vid.mode.width;
10179         y1 = (vid.mode.height - s[0][1]) * vid_conheight.value / vid.mode.height;
10180         x2 = s[1][0] * vid_conwidth.value / vid.mode.width;
10181         y2 = (vid.mode.height - s[1][1]) * vid_conheight.value / vid.mode.height;
10182         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10183
10184         // add the line to the UI mesh for drawing later
10185
10186         // width is measured in real pixels
10187         if (fabs(x2 - x1) > fabs(y2 - y1))
10188         {
10189                 offsetx = 0;
10190                 offsety = 0.5f * width * vid_conheight.value / vid.mode.height;
10191         }
10192         else
10193         {
10194                 offsetx = 0.5f * width * vid_conwidth.value / vid.mode.width;
10195                 offsety = 0;
10196         }
10197         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);
10198         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10199         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10200         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10201         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10202         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10203         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10204
10205 }
10206
10207
10208 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)
10209 {
10210         static texture_t texture;
10211
10212         // fake enough texture and surface state to render this geometry
10213
10214         texture.update_lastrenderframe = -1; // regenerate this texture
10215         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10216         texture.basealpha = 1.0f;
10217         texture.currentskinframe = skinframe;
10218         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10219         texture.offsetmapping = OFFSETMAPPING_OFF;
10220         texture.offsetscale = 1;
10221         texture.specularscalemod = 1;
10222         texture.specularpowermod = 1;
10223         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10224
10225         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10226 }
10227
10228 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)
10229 {
10230         static msurface_t surface;
10231         const msurface_t *surfacelist = &surface;
10232
10233         // fake enough texture and surface state to render this geometry
10234         surface.texture = texture;
10235         surface.num_triangles = numtriangles;
10236         surface.num_firsttriangle = firsttriangle;
10237         surface.num_vertices = numvertices;
10238         surface.num_firstvertex = firstvertex;
10239
10240         // now render it
10241         rsurface.texture = R_GetCurrentTexture(surface.texture);
10242         rsurface.lightmaptexture = NULL;
10243         rsurface.deluxemaptexture = NULL;
10244         rsurface.uselightmaptexture = false;
10245         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10246 }