]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Organize system and host globals into structs. Implement host state tracking
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_CLIENT | CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_CLIENT | CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CVAR_CLIENT | CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
73 cvar_t r_useinfinitefarclip = {CVAR_CLIENT | CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CVAR_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CVAR_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CVAR_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CVAR_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CVAR_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CVAR_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CVAR_CLIENT, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
81 cvar_t r_transparent_useplanardistance = {CVAR_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CVAR_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CVAR_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CVAR_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CVAR_CLIENT, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
86 cvar_t r_showtris = {CVAR_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CVAR_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CVAR_CLIENT, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
89 cvar_t r_showcollisionbrushes = {CVAR_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CVAR_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CVAR_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CVAR_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CVAR_CLIENT, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
94 cvar_t r_showparticleedges = {CVAR_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CVAR_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CVAR_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CVAR_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CVAR_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CVAR_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CVAR_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CVAR_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CVAR_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CVAR_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CVAR_CLIENT, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
105 cvar_t r_cullentities_trace_enlarge = {CVAR_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CVAR_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CVAR_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CVAR_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CVAR_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CVAR_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CVAR_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CVAR_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CVAR_CLIENT, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
115 cvar_t r_fullbright_directed_ambient = {CVAR_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CVAR_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CVAR_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CVAR_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CVAR_CLIENT | CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CVAR_CLIENT | CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CVAR_CLIENT | CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CVAR_CLIENT | CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
124 cvar_t r_shadows_darken = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
128 cvar_t r_shadows_castfrombmodels = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
131 cvar_t r_shadows_shadowmapbias = {CVAR_CLIENT | CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CVAR_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CVAR_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CVAR_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CVAR_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CVAR_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CVAR_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CVAR_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CVAR_CLIENT | CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CVAR_CLIENT | CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CVAR_CLIENT | CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CVAR_CLIENT | CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CVAR_CLIENT | CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CVAR_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CVAR_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CVAR_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CVAR_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CVAR_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CVAR_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CVAR_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CVAR_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CVAR_CLIENT | CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
158
159 cvar_t r_textureunits = {CVAR_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CVAR_CLIENT | CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CVAR_CLIENT | CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CVAR_CLIENT | CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
164 cvar_t r_viewfbo = {CVAR_CLIENT | CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
165 cvar_t r_rendertarget_debug = {CVAR_CLIENT, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
166 cvar_t r_viewscale = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
167 cvar_t r_viewscale_fpsscaling = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CVAR_CLIENT | CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
181 cvar_t r_glsl_offsetmapping_scale = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194
195 cvar_t r_water = {CVAR_CLIENT | CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
196 cvar_t r_water_cameraentitiesonly = {CVAR_CLIENT | CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
197 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
198 cvar_t r_water_resolutionmultiplier = {CVAR_CLIENT | CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
199 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
200 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
201 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
202 cvar_t r_water_lowquality = {CVAR_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
203 cvar_t r_water_hideplayer = {CVAR_CLIENT | CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
204
205 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
206 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
207 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
208 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
209
210 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
211 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
212
213 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
214 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
215 cvar_t r_bloom_resolution = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
216 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
217 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
218 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
219
220 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
221 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
222 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
223 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
224 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
225 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
227 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
228 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
229 cvar_t r_hdr_irisadaptation_radius = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
230
231 cvar_t r_smoothnormals_areaweighting = {CVAR_CLIENT, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
232
233 cvar_t developer_texturelogging = {CVAR_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
234
235 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
236
237 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
238
239 cvar_t r_batch_multidraw = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
240 cvar_t r_batch_multidraw_mintriangles = {CVAR_CLIENT | CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
241 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
242 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
243
244 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
245 cvar_t r_glsl_saturation_redcompensate = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
246
247 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
248
249 cvar_t r_framedatasize = {CVAR_CLIENT | CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
250 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
251 {
252         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
256 };
257
258 extern cvar_t v_glslgamma_2d;
259
260 extern qboolean v_flipped_state;
261
262 r_framebufferstate_t r_fb;
263
264 /// shadow volume bsp struct with automatically growing nodes buffer
265 svbsp_t r_svbsp;
266
267 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
268
269 rtexture_t *r_texture_blanknormalmap;
270 rtexture_t *r_texture_white;
271 rtexture_t *r_texture_grey128;
272 rtexture_t *r_texture_black;
273 rtexture_t *r_texture_notexture;
274 rtexture_t *r_texture_whitecube;
275 rtexture_t *r_texture_normalizationcube;
276 rtexture_t *r_texture_fogattenuation;
277 rtexture_t *r_texture_fogheighttexture;
278 rtexture_t *r_texture_gammaramps;
279 unsigned int r_texture_gammaramps_serial;
280 //rtexture_t *r_texture_fogintensity;
281 rtexture_t *r_texture_reflectcube;
282
283 // TODO: hash lookups?
284 typedef struct cubemapinfo_s
285 {
286         char basename[64];
287         rtexture_t *texture;
288 }
289 cubemapinfo_t;
290
291 int r_texture_numcubemaps;
292 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
293
294 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
295 unsigned int r_numqueries;
296 unsigned int r_maxqueries;
297
298 typedef struct r_qwskincache_s
299 {
300         char name[MAX_QPATH];
301         skinframe_t *skinframe;
302 }
303 r_qwskincache_t;
304
305 static r_qwskincache_t *r_qwskincache;
306 static int r_qwskincache_size;
307
308 /// vertex coordinates for a quad that covers the screen exactly
309 extern const float r_screenvertex3f[12];
310 const float r_screenvertex3f[12] =
311 {
312         0, 0, 0,
313         1, 0, 0,
314         1, 1, 0,
315         0, 1, 0
316 };
317
318 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
319 {
320         int i;
321         for (i = 0;i < verts;i++)
322         {
323                 out[0] = in[0] * r;
324                 out[1] = in[1] * g;
325                 out[2] = in[2] * b;
326                 out[3] = in[3];
327                 in += 4;
328                 out += 4;
329         }
330 }
331
332 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
333 {
334         int i;
335         for (i = 0;i < verts;i++)
336         {
337                 out[0] = r;
338                 out[1] = g;
339                 out[2] = b;
340                 out[3] = a;
341                 out += 4;
342         }
343 }
344
345 // FIXME: move this to client?
346 void FOG_clear(void)
347 {
348         if (gamemode == GAME_NEHAHRA)
349         {
350                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
351                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
352                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
353                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
354                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
355         }
356         r_refdef.fog_density = 0;
357         r_refdef.fog_red = 0;
358         r_refdef.fog_green = 0;
359         r_refdef.fog_blue = 0;
360         r_refdef.fog_alpha = 1;
361         r_refdef.fog_start = 0;
362         r_refdef.fog_end = 16384;
363         r_refdef.fog_height = 1<<30;
364         r_refdef.fog_fadedepth = 128;
365         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
366 }
367
368 static void R_BuildBlankTextures(void)
369 {
370         unsigned char data[4];
371         data[2] = 128; // normal X
372         data[1] = 128; // normal Y
373         data[0] = 255; // normal Z
374         data[3] = 255; // height
375         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
376         data[0] = 255;
377         data[1] = 255;
378         data[2] = 255;
379         data[3] = 255;
380         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
381         data[0] = 128;
382         data[1] = 128;
383         data[2] = 128;
384         data[3] = 255;
385         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 0;
387         data[1] = 0;
388         data[2] = 0;
389         data[3] = 255;
390         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391 }
392
393 static void R_BuildNoTexture(void)
394 {
395         int x, y;
396         unsigned char pix[16][16][4];
397         // this makes a light grey/dark grey checkerboard texture
398         for (y = 0;y < 16;y++)
399         {
400                 for (x = 0;x < 16;x++)
401                 {
402                         if ((y < 8) ^ (x < 8))
403                         {
404                                 pix[y][x][0] = 128;
405                                 pix[y][x][1] = 128;
406                                 pix[y][x][2] = 128;
407                                 pix[y][x][3] = 255;
408                         }
409                         else
410                         {
411                                 pix[y][x][0] = 64;
412                                 pix[y][x][1] = 64;
413                                 pix[y][x][2] = 64;
414                                 pix[y][x][3] = 255;
415                         }
416                 }
417         }
418         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
419 }
420
421 static void R_BuildWhiteCube(void)
422 {
423         unsigned char data[6*1*1*4];
424         memset(data, 255, sizeof(data));
425         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
426 }
427
428 static void R_BuildNormalizationCube(void)
429 {
430         int x, y, side;
431         vec3_t v;
432         vec_t s, t, intensity;
433 #define NORMSIZE 64
434         unsigned char *data;
435         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
436         for (side = 0;side < 6;side++)
437         {
438                 for (y = 0;y < NORMSIZE;y++)
439                 {
440                         for (x = 0;x < NORMSIZE;x++)
441                         {
442                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
443                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
444                                 switch(side)
445                                 {
446                                 default:
447                                 case 0:
448                                         v[0] = 1;
449                                         v[1] = -t;
450                                         v[2] = -s;
451                                         break;
452                                 case 1:
453                                         v[0] = -1;
454                                         v[1] = -t;
455                                         v[2] = s;
456                                         break;
457                                 case 2:
458                                         v[0] = s;
459                                         v[1] = 1;
460                                         v[2] = t;
461                                         break;
462                                 case 3:
463                                         v[0] = s;
464                                         v[1] = -1;
465                                         v[2] = -t;
466                                         break;
467                                 case 4:
468                                         v[0] = s;
469                                         v[1] = -t;
470                                         v[2] = 1;
471                                         break;
472                                 case 5:
473                                         v[0] = -s;
474                                         v[1] = -t;
475                                         v[2] = -1;
476                                         break;
477                                 }
478                                 intensity = 127.0f / sqrt(DotProduct(v, v));
479                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
480                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
481                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
482                                 data[((side*64+y)*64+x)*4+3] = 255;
483                         }
484                 }
485         }
486         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
487         Mem_Free(data);
488 }
489
490 static void R_BuildFogTexture(void)
491 {
492         int x, b;
493 #define FOGWIDTH 256
494         unsigned char data1[FOGWIDTH][4];
495         //unsigned char data2[FOGWIDTH][4];
496         double d, r, alpha;
497
498         r_refdef.fogmasktable_start = r_refdef.fog_start;
499         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
500         r_refdef.fogmasktable_range = r_refdef.fogrange;
501         r_refdef.fogmasktable_density = r_refdef.fog_density;
502
503         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
504         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
505         {
506                 d = (x * r - r_refdef.fogmasktable_start);
507                 if(developer_extra.integer)
508                         Con_DPrintf("%f ", d);
509                 d = max(0, d);
510                 if (r_fog_exp2.integer)
511                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
512                 else
513                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
514                 if(developer_extra.integer)
515                         Con_DPrintf(" : %f ", alpha);
516                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
517                 if(developer_extra.integer)
518                         Con_DPrintf(" = %f\n", alpha);
519                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
520         }
521
522         for (x = 0;x < FOGWIDTH;x++)
523         {
524                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
525                 data1[x][0] = b;
526                 data1[x][1] = b;
527                 data1[x][2] = b;
528                 data1[x][3] = 255;
529                 //data2[x][0] = 255 - b;
530                 //data2[x][1] = 255 - b;
531                 //data2[x][2] = 255 - b;
532                 //data2[x][3] = 255;
533         }
534         if (r_texture_fogattenuation)
535         {
536                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
537                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
538         }
539         else
540         {
541                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
542                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
543         }
544 }
545
546 static void R_BuildFogHeightTexture(void)
547 {
548         unsigned char *inpixels;
549         int size;
550         int x;
551         int y;
552         int j;
553         float c[4];
554         float f;
555         inpixels = NULL;
556         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
557         if (r_refdef.fogheighttexturename[0])
558                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
559         if (!inpixels)
560         {
561                 r_refdef.fog_height_tablesize = 0;
562                 if (r_texture_fogheighttexture)
563                         R_FreeTexture(r_texture_fogheighttexture);
564                 r_texture_fogheighttexture = NULL;
565                 if (r_refdef.fog_height_table2d)
566                         Mem_Free(r_refdef.fog_height_table2d);
567                 r_refdef.fog_height_table2d = NULL;
568                 if (r_refdef.fog_height_table1d)
569                         Mem_Free(r_refdef.fog_height_table1d);
570                 r_refdef.fog_height_table1d = NULL;
571                 return;
572         }
573         size = image_width;
574         r_refdef.fog_height_tablesize = size;
575         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
576         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
577         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
578         Mem_Free(inpixels);
579         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
580         // average fog color table accounting for every fog layer between a point
581         // and the camera.  (Note: attenuation is handled separately!)
582         for (y = 0;y < size;y++)
583         {
584                 for (x = 0;x < size;x++)
585                 {
586                         Vector4Clear(c);
587                         f = 0;
588                         if (x < y)
589                         {
590                                 for (j = x;j <= y;j++)
591                                 {
592                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
593                                         f++;
594                                 }
595                         }
596                         else
597                         {
598                                 for (j = x;j >= y;j--)
599                                 {
600                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
601                                         f++;
602                                 }
603                         }
604                         f = 1.0f / f;
605                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
606                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
607                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
608                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
609                 }
610         }
611         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
612 }
613
614 //=======================================================================================================================================================
615
616 static const char *builtinshaderstrings[] =
617 {
618 #include "shader_glsl.h"
619 0
620 };
621
622 //=======================================================================================================================================================
623
624 typedef struct shaderpermutationinfo_s
625 {
626         const char *pretext;
627         const char *name;
628 }
629 shaderpermutationinfo_t;
630
631 typedef struct shadermodeinfo_s
632 {
633         const char *sourcebasename;
634         const char *extension;
635         const char **builtinshaderstrings;
636         const char *pretext;
637         const char *name;
638         char *filename;
639         char *builtinstring;
640         int builtincrc;
641 }
642 shadermodeinfo_t;
643
644 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
645 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
646 {
647         {"#define USEDIFFUSE\n", " diffuse"},
648         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
649         {"#define USEVIEWTINT\n", " viewtint"},
650         {"#define USECOLORMAPPING\n", " colormapping"},
651         {"#define USESATURATION\n", " saturation"},
652         {"#define USEFOGINSIDE\n", " foginside"},
653         {"#define USEFOGOUTSIDE\n", " fogoutside"},
654         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
655         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
656         {"#define USEGAMMARAMPS\n", " gammaramps"},
657         {"#define USECUBEFILTER\n", " cubefilter"},
658         {"#define USEGLOW\n", " glow"},
659         {"#define USEBLOOM\n", " bloom"},
660         {"#define USESPECULAR\n", " specular"},
661         {"#define USEPOSTPROCESSING\n", " postprocessing"},
662         {"#define USEREFLECTION\n", " reflection"},
663         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
664         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
665         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
666         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
667         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
668         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
669         {"#define USEALPHAKILL\n", " alphakill"},
670         {"#define USEREFLECTCUBE\n", " reflectcube"},
671         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
672         {"#define USEBOUNCEGRID\n", " bouncegrid"},
673         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
674         {"#define USETRIPPY\n", " trippy"},
675         {"#define USEDEPTHRGB\n", " depthrgb"},
676         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
677         {"#define USESKELETAL\n", " skeletal"},
678         {"#define USEOCCLUDE\n", " occlude"}
679 };
680
681 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
682 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
683 {
684         // SHADERLANGUAGE_GLSL
685         {
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
687                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
688                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
689                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
690                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
691                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
692                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
693                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
694                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
695                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
703         },
704 };
705
706 struct r_glsl_permutation_s;
707 typedef struct r_glsl_permutation_s
708 {
709         /// hash lookup data
710         struct r_glsl_permutation_s *hashnext;
711         unsigned int mode;
712         uint64_t permutation;
713
714         /// indicates if we have tried compiling this permutation already
715         qboolean compiled;
716         /// 0 if compilation failed
717         int program;
718         // texture units assigned to each detected uniform
719         int tex_Texture_First;
720         int tex_Texture_Second;
721         int tex_Texture_GammaRamps;
722         int tex_Texture_Normal;
723         int tex_Texture_Color;
724         int tex_Texture_Gloss;
725         int tex_Texture_Glow;
726         int tex_Texture_SecondaryNormal;
727         int tex_Texture_SecondaryColor;
728         int tex_Texture_SecondaryGloss;
729         int tex_Texture_SecondaryGlow;
730         int tex_Texture_Pants;
731         int tex_Texture_Shirt;
732         int tex_Texture_FogHeightTexture;
733         int tex_Texture_FogMask;
734         int tex_Texture_LightGrid;
735         int tex_Texture_Lightmap;
736         int tex_Texture_Deluxemap;
737         int tex_Texture_Attenuation;
738         int tex_Texture_Cube;
739         int tex_Texture_Refraction;
740         int tex_Texture_Reflection;
741         int tex_Texture_ShadowMap2D;
742         int tex_Texture_CubeProjection;
743         int tex_Texture_ScreenNormalMap;
744         int tex_Texture_ScreenDiffuse;
745         int tex_Texture_ScreenSpecular;
746         int tex_Texture_ReflectMask;
747         int tex_Texture_ReflectCube;
748         int tex_Texture_BounceGrid;
749         /// locations of detected uniforms in program object, or -1 if not found
750         int loc_Texture_First;
751         int loc_Texture_Second;
752         int loc_Texture_GammaRamps;
753         int loc_Texture_Normal;
754         int loc_Texture_Color;
755         int loc_Texture_Gloss;
756         int loc_Texture_Glow;
757         int loc_Texture_SecondaryNormal;
758         int loc_Texture_SecondaryColor;
759         int loc_Texture_SecondaryGloss;
760         int loc_Texture_SecondaryGlow;
761         int loc_Texture_Pants;
762         int loc_Texture_Shirt;
763         int loc_Texture_FogHeightTexture;
764         int loc_Texture_FogMask;
765         int loc_Texture_LightGrid;
766         int loc_Texture_Lightmap;
767         int loc_Texture_Deluxemap;
768         int loc_Texture_Attenuation;
769         int loc_Texture_Cube;
770         int loc_Texture_Refraction;
771         int loc_Texture_Reflection;
772         int loc_Texture_ShadowMap2D;
773         int loc_Texture_CubeProjection;
774         int loc_Texture_ScreenNormalMap;
775         int loc_Texture_ScreenDiffuse;
776         int loc_Texture_ScreenSpecular;
777         int loc_Texture_ReflectMask;
778         int loc_Texture_ReflectCube;
779         int loc_Texture_BounceGrid;
780         int loc_Alpha;
781         int loc_BloomBlur_Parameters;
782         int loc_ClientTime;
783         int loc_Color_Ambient;
784         int loc_Color_Diffuse;
785         int loc_Color_Specular;
786         int loc_Color_Glow;
787         int loc_Color_Pants;
788         int loc_Color_Shirt;
789         int loc_DeferredColor_Ambient;
790         int loc_DeferredColor_Diffuse;
791         int loc_DeferredColor_Specular;
792         int loc_DeferredMod_Diffuse;
793         int loc_DeferredMod_Specular;
794         int loc_DistortScaleRefractReflect;
795         int loc_EyePosition;
796         int loc_FogColor;
797         int loc_FogHeightFade;
798         int loc_FogPlane;
799         int loc_FogPlaneViewDist;
800         int loc_FogRangeRecip;
801         int loc_LightColor;
802         int loc_LightDir;
803         int loc_LightGridMatrix;
804         int loc_LightGridNormalMatrix;
805         int loc_LightPosition;
806         int loc_OffsetMapping_ScaleSteps;
807         int loc_OffsetMapping_LodDistance;
808         int loc_OffsetMapping_Bias;
809         int loc_PixelSize;
810         int loc_ReflectColor;
811         int loc_ReflectFactor;
812         int loc_ReflectOffset;
813         int loc_RefractColor;
814         int loc_Saturation;
815         int loc_ScreenCenterRefractReflect;
816         int loc_ScreenScaleRefractReflect;
817         int loc_ScreenToDepth;
818         int loc_ShadowMap_Parameters;
819         int loc_ShadowMap_TextureScale;
820         int loc_SpecularPower;
821         int loc_Skeletal_Transform12;
822         int loc_UserVec1;
823         int loc_UserVec2;
824         int loc_UserVec3;
825         int loc_UserVec4;
826         int loc_ColorFringe;
827         int loc_ViewTintColor;
828         int loc_ViewToLight;
829         int loc_ModelToLight;
830         int loc_TexMatrix;
831         int loc_BackgroundTexMatrix;
832         int loc_ModelViewProjectionMatrix;
833         int loc_ModelViewMatrix;
834         int loc_PixelToScreenTexCoord;
835         int loc_ModelToReflectCube;
836         int loc_ShadowMapMatrix;
837         int loc_BloomColorSubtract;
838         int loc_NormalmapScrollBlend;
839         int loc_BounceGridMatrix;
840         int loc_BounceGridIntensity;
841         /// uniform block bindings
842         int ubibind_Skeletal_Transform12_UniformBlock;
843         /// uniform block indices
844         int ubiloc_Skeletal_Transform12_UniformBlock;
845 }
846 r_glsl_permutation_t;
847
848 #define SHADERPERMUTATION_HASHSIZE 256
849
850
851 // non-degradable "lightweight" shader parameters to keep the permutations simpler
852 // these can NOT degrade! only use for simple stuff
853 enum
854 {
855         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
856         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
857         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
858         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
859         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
860         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
861         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
862         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
863         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
864         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
865         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
866         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
867         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
868         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
869 };
870 #define SHADERSTATICPARMS_COUNT 14
871
872 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
873 static int shaderstaticparms_count = 0;
874
875 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
876 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
877
878 extern qboolean r_shadow_shadowmapsampler;
879 extern int r_shadow_shadowmappcf;
880 qboolean R_CompileShader_CheckStaticParms(void)
881 {
882         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
883         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
884         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
885
886         // detect all
887         if (r_glsl_saturation_redcompensate.integer)
888                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
889         if (r_glsl_vertextextureblend_usebothalphas.integer)
890                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
891         if (r_shadow_glossexact.integer)
892                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
893         if (r_glsl_postprocess.integer)
894         {
895                 if (r_glsl_postprocess_uservec1_enable.integer)
896                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
897                 if (r_glsl_postprocess_uservec2_enable.integer)
898                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
899                 if (r_glsl_postprocess_uservec3_enable.integer)
900                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
901                 if (r_glsl_postprocess_uservec4_enable.integer)
902                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
903         }
904         if (r_fxaa.integer)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
906         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
907                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
908
909         if (r_shadow_shadowmapsampler)
910                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
911         if (r_shadow_shadowmappcf > 1)
912                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
913         else if (r_shadow_shadowmappcf)
914                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
915         if (r_celshading.integer)
916                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
917         if (r_celoutlines.integer)
918                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
919
920         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
921 }
922
923 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
924         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
925                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
926         else \
927                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
928 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
929 {
930         shaderstaticparms_count = 0;
931
932         // emit all
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
935         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
936         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
937         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
947 }
948
949 /// information about each possible shader permutation
950 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
951 /// currently selected permutation
952 r_glsl_permutation_t *r_glsl_permutation;
953 /// storage for permutations linked in the hash table
954 memexpandablearray_t r_glsl_permutationarray;
955
956 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
957 {
958         //unsigned int hashdepth = 0;
959         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
960         r_glsl_permutation_t *p;
961         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
962         {
963                 if (p->mode == mode && p->permutation == permutation)
964                 {
965                         //if (hashdepth > 10)
966                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
967                         return p;
968                 }
969                 //hashdepth++;
970         }
971         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
972         p->mode = mode;
973         p->permutation = permutation;
974         p->hashnext = r_glsl_permutationhash[mode][hashindex];
975         r_glsl_permutationhash[mode][hashindex] = p;
976         //if (hashdepth > 10)
977         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
978         return p;
979 }
980
981 static char *R_ShaderStrCat(const char **strings)
982 {
983         char *string, *s;
984         const char **p = strings;
985         const char *t;
986         size_t len = 0;
987         for (p = strings;(t = *p);p++)
988                 len += strlen(t);
989         len++;
990         s = string = (char *)Mem_Alloc(r_main_mempool, len);
991         len = 0;
992         for (p = strings;(t = *p);p++)
993         {
994                 len = strlen(t);
995                 memcpy(s, t, len);
996                 s += len;
997         }
998         *s = 0;
999         return string;
1000 }
1001
1002 static char *R_ShaderStrCat(const char **strings);
1003 static void R_InitShaderModeInfo(void)
1004 {
1005         int i, language;
1006         shadermodeinfo_t *modeinfo;
1007         // 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)
1008         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1009         {
1010                 for (i = 0; i < SHADERMODE_COUNT; i++)
1011                 {
1012                         char filename[MAX_QPATH];
1013                         modeinfo = &shadermodeinfo[language][i];
1014                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1015                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1016                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1017                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1018                 }
1019         }
1020 }
1021
1022 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1023 {
1024         char *shaderstring;
1025         // if the mode has no filename we have to return the builtin string
1026         if (builtinonly || !modeinfo->filename)
1027                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1028         // note that FS_LoadFile appends a 0 byte to make it a valid string
1029         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1030         if (shaderstring)
1031         {
1032                 if (printfromdisknotice)
1033                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1034                 return shaderstring;
1035         }
1036         // fall back to builtinstring
1037         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1038 }
1039
1040 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1041 {
1042         int i;
1043         int ubibind;
1044         int sampler;
1045         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1046         char *sourcestring;
1047         char permutationname[256];
1048         int vertstrings_count = 0;
1049         int geomstrings_count = 0;
1050         int fragstrings_count = 0;
1051         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1052         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1053         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1054
1055         if (p->compiled)
1056                 return;
1057         p->compiled = true;
1058         p->program = 0;
1059
1060         permutationname[0] = 0;
1061         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1062
1063         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1064
1065         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1066         if(vid.support.glshaderversion >= 140)
1067         {
1068                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1069                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1070                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1071                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1072                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1073                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1074         }
1075         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1076         else if(vid.support.glshaderversion >= 130)
1077         {
1078                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1079                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1080                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1081                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1082                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1083                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1084         }
1085         // if we can do #version 120, we should (this adds the invariant keyword)
1086         else if(vid.support.glshaderversion >= 120)
1087         {
1088                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1089                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1090                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1091                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1092                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1093                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1094         }
1095         // GLES also adds several things from GLSL120
1096         switch(vid.renderpath)
1097         {
1098         case RENDERPATH_GLES2:
1099                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1100                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1101                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1102                 break;
1103         default:
1104                 break;
1105         }
1106
1107         // the first pretext is which type of shader to compile as
1108         // (later these will all be bound together as a program object)
1109         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1110         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1111         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1112
1113         // the second pretext is the mode (for example a light source)
1114         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1115         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1116         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1117         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1118
1119         // now add all the permutation pretexts
1120         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1121         {
1122                 if (permutation & (1ll<<i))
1123                 {
1124                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1125                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1126                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1127                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1128                 }
1129                 else
1130                 {
1131                         // keep line numbers correct
1132                         vertstrings_list[vertstrings_count++] = "\n";
1133                         geomstrings_list[geomstrings_count++] = "\n";
1134                         fragstrings_list[fragstrings_count++] = "\n";
1135                 }
1136         }
1137
1138         // add static parms
1139         R_CompileShader_AddStaticParms(mode, permutation);
1140         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1141         vertstrings_count += shaderstaticparms_count;
1142         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1143         geomstrings_count += shaderstaticparms_count;
1144         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1145         fragstrings_count += shaderstaticparms_count;
1146
1147         // now append the shader text itself
1148         vertstrings_list[vertstrings_count++] = sourcestring;
1149         geomstrings_list[geomstrings_count++] = sourcestring;
1150         fragstrings_list[fragstrings_count++] = sourcestring;
1151
1152         // we don't currently use geometry shaders for anything, so just empty the list
1153         geomstrings_count = 0;
1154
1155         // compile the shader program
1156         if (vertstrings_count + geomstrings_count + fragstrings_count)
1157                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1158         if (p->program)
1159         {
1160                 CHECKGLERROR
1161                 qglUseProgram(p->program);CHECKGLERROR
1162                 // look up all the uniform variable names we care about, so we don't
1163                 // have to look them up every time we set them
1164
1165 #if 0
1166                 // debugging aid
1167                 {
1168                         GLint activeuniformindex = 0;
1169                         GLint numactiveuniforms = 0;
1170                         char uniformname[128];
1171                         GLsizei uniformnamelength = 0;
1172                         GLint uniformsize = 0;
1173                         GLenum uniformtype = 0;
1174                         memset(uniformname, 0, sizeof(uniformname));
1175                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1176                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1177                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1178                         {
1179                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1180                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1181                         }
1182                 }
1183 #endif
1184
1185                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1186                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1187                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1188                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1189                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1190                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1191                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1192                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1193                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1194                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1195                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1196                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1197                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1198                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1199                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1200                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1201                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1202                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1203                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1204                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1205                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1206                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1207                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1208                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1209                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1210                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1211                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1212                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1213                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1214                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1215                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1216                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1217                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1218                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1219                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1220                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1221                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1222                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1223                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1224                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1225                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1226                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1227                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1228                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1229                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1230                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1231                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1232                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1233                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1234                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1235                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1236                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1237                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1238                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1239                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1240                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1241                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1242                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1243                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1244                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1245                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1246                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1247                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1248                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1249                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1250                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1251                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1252                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1253                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1254                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1255                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1256                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1257                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1258                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1259                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1260                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1261                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1262                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1263                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1264                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1265                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1266                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1267                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1268                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1269                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1270                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1271                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1272                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1273                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1274                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1275                 // initialize the samplers to refer to the texture units we use
1276                 p->tex_Texture_First = -1;
1277                 p->tex_Texture_Second = -1;
1278                 p->tex_Texture_GammaRamps = -1;
1279                 p->tex_Texture_Normal = -1;
1280                 p->tex_Texture_Color = -1;
1281                 p->tex_Texture_Gloss = -1;
1282                 p->tex_Texture_Glow = -1;
1283                 p->tex_Texture_SecondaryNormal = -1;
1284                 p->tex_Texture_SecondaryColor = -1;
1285                 p->tex_Texture_SecondaryGloss = -1;
1286                 p->tex_Texture_SecondaryGlow = -1;
1287                 p->tex_Texture_Pants = -1;
1288                 p->tex_Texture_Shirt = -1;
1289                 p->tex_Texture_FogHeightTexture = -1;
1290                 p->tex_Texture_FogMask = -1;
1291                 p->tex_Texture_LightGrid = -1;
1292                 p->tex_Texture_Lightmap = -1;
1293                 p->tex_Texture_Deluxemap = -1;
1294                 p->tex_Texture_Attenuation = -1;
1295                 p->tex_Texture_Cube = -1;
1296                 p->tex_Texture_Refraction = -1;
1297                 p->tex_Texture_Reflection = -1;
1298                 p->tex_Texture_ShadowMap2D = -1;
1299                 p->tex_Texture_CubeProjection = -1;
1300                 p->tex_Texture_ScreenNormalMap = -1;
1301                 p->tex_Texture_ScreenDiffuse = -1;
1302                 p->tex_Texture_ScreenSpecular = -1;
1303                 p->tex_Texture_ReflectMask = -1;
1304                 p->tex_Texture_ReflectCube = -1;
1305                 p->tex_Texture_BounceGrid = -1;
1306                 // bind the texture samplers in use
1307                 sampler = 0;
1308                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1309                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1310                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1311                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1312                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1313                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1314                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1315                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1316                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1317                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1318                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1319                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1320                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1321                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1322                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1323                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1324                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1325                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1326                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1327                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1328                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1329                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1330                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1331                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1332                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1333                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1334                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1335                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1336                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1337                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1338                 // get the uniform block indices so we can bind them
1339                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1340 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1341                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1342 #endif
1343                 // clear the uniform block bindings
1344                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1345                 // bind the uniform blocks in use
1346                 ubibind = 0;
1347 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1348                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1349 #endif
1350                 // we're done compiling and setting up the shader, at least until it is used
1351                 CHECKGLERROR
1352                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1353         }
1354         else
1355                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1356
1357         // free the strings
1358         if (sourcestring)
1359                 Mem_Free(sourcestring);
1360 }
1361
1362 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1363 {
1364         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1365         if (r_glsl_permutation != perm)
1366         {
1367                 r_glsl_permutation = perm;
1368                 if (!r_glsl_permutation->program)
1369                 {
1370                         if (!r_glsl_permutation->compiled)
1371                         {
1372                                 Con_DPrintf("Compiling shader mode %u permutation %"PRIx64"\n", mode, permutation);
1373                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1374                         }
1375                         if (!r_glsl_permutation->program)
1376                         {
1377                                 // remove features until we find a valid permutation
1378                                 int i;
1379                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1380                                 {
1381                                         // reduce i more quickly whenever it would not remove any bits
1382                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1383                                         if (!(permutation & j))
1384                                                 continue;
1385                                         permutation -= j;
1386                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1387                                         if (!r_glsl_permutation->compiled)
1388                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1389                                         if (r_glsl_permutation->program)
1390                                                 break;
1391                                 }
1392                                 if (i >= SHADERPERMUTATION_COUNT)
1393                                 {
1394                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1395                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1396                                         qglUseProgram(0);CHECKGLERROR
1397                                         return; // no bit left to clear, entire mode is broken
1398                                 }
1399                         }
1400                 }
1401                 CHECKGLERROR
1402                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1403         }
1404         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1405         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1406         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1407         CHECKGLERROR
1408 }
1409
1410 void R_GLSL_Restart_f(cmd_state_t *cmd)
1411 {
1412         unsigned int i, limit;
1413         switch(vid.renderpath)
1414         {
1415         case RENDERPATH_GL32:
1416         case RENDERPATH_GLES2:
1417                 {
1418                         r_glsl_permutation_t *p;
1419                         r_glsl_permutation = NULL;
1420                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1421                         for (i = 0;i < limit;i++)
1422                         {
1423                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1424                                 {
1425                                         GL_Backend_FreeProgram(p->program);
1426                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1427                                 }
1428                         }
1429                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1430                 }
1431                 break;
1432         }
1433 }
1434
1435 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1436 {
1437         int i, language, mode, dupe;
1438         char *text;
1439         shadermodeinfo_t *modeinfo;
1440         qfile_t *file;
1441
1442         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1443         {
1444                 modeinfo = shadermodeinfo[language];
1445                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1446                 {
1447                         // don't dump the same file multiple times (most or all shaders come from the same file)
1448                         for (dupe = mode - 1;dupe >= 0;dupe--)
1449                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1450                                         break;
1451                         if (dupe >= 0)
1452                                 continue;
1453                         text = modeinfo[mode].builtinstring;
1454                         if (!text)
1455                                 continue;
1456                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1457                         if (file)
1458                         {
1459                                 FS_Print(file, "/* The engine may define the following macros:\n");
1460                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1461                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1462                                         FS_Print(file, modeinfo[i].pretext);
1463                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1464                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1465                                 FS_Print(file, "*/\n");
1466                                 FS_Print(file, text);
1467                                 FS_Close(file);
1468                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1469                         }
1470                         else
1471                                 Con_Errorf("failed to write to %s\n", modeinfo[mode].filename);
1472                 }
1473         }
1474 }
1475
1476 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1477 {
1478         uint64_t permutation = 0;
1479         if (r_trippy.integer && !notrippy)
1480                 permutation |= SHADERPERMUTATION_TRIPPY;
1481         permutation |= SHADERPERMUTATION_VIEWTINT;
1482         if (t)
1483                 permutation |= SHADERPERMUTATION_DIFFUSE;
1484         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1485                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1486         if (suppresstexalpha)
1487                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1488         if (vid.allowalphatocoverage)
1489                 GL_AlphaToCoverage(false);
1490         switch (vid.renderpath)
1491         {
1492         case RENDERPATH_GL32:
1493         case RENDERPATH_GLES2:
1494                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1495                 if (r_glsl_permutation->tex_Texture_First >= 0)
1496                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1497                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1498                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1499                 break;
1500         }
1501 }
1502
1503 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1504 {
1505         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1506 }
1507
1508 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1509 {
1510         uint64_t permutation = 0;
1511         if (r_trippy.integer && !notrippy)
1512                 permutation |= SHADERPERMUTATION_TRIPPY;
1513         if (depthrgb)
1514                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1515         if (skeletal)
1516                 permutation |= SHADERPERMUTATION_SKELETAL;
1517
1518         if (vid.allowalphatocoverage)
1519                 GL_AlphaToCoverage(false);
1520         switch (vid.renderpath)
1521         {
1522         case RENDERPATH_GL32:
1523         case RENDERPATH_GLES2:
1524                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1525 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1526                 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);
1527 #endif
1528                 break;
1529         }
1530 }
1531
1532 #define BLENDFUNC_ALLOWS_COLORMOD      1
1533 #define BLENDFUNC_ALLOWS_FOG           2
1534 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1535 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1536 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1537 static int R_BlendFuncFlags(int src, int dst)
1538 {
1539         int r = 0;
1540
1541         // a blendfunc allows colormod if:
1542         // a) it can never keep the destination pixel invariant, or
1543         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1544         // this is to prevent unintended side effects from colormod
1545
1546         // a blendfunc allows fog if:
1547         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1548         // this is to prevent unintended side effects from fog
1549
1550         // these checks are the output of fogeval.pl
1551
1552         r |= BLENDFUNC_ALLOWS_COLORMOD;
1553         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1554         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1555         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1556         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1557         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1558         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1559         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1560         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1561         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1562         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1563         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1564         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1565         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1566         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1567         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1568         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1571         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1572         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1574
1575         return r;
1576 }
1577
1578 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1579 {
1580         // select a permutation of the lighting shader appropriate to this
1581         // combination of texture, entity, light source, and fogging, only use the
1582         // minimum features necessary to avoid wasting rendering time in the
1583         // fragment shader on features that are not being used
1584         uint64_t permutation = 0;
1585         unsigned int mode = 0;
1586         int blendfuncflags;
1587         texture_t *t = rsurface.texture;
1588         float m16f[16];
1589         matrix4x4_t tempmatrix;
1590         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1591         if (r_trippy.integer && !notrippy)
1592                 permutation |= SHADERPERMUTATION_TRIPPY;
1593         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1594                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1595         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1596                 permutation |= SHADERPERMUTATION_OCCLUDE;
1597         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1598                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1599         if (rsurfacepass == RSURFPASS_BACKGROUND)
1600         {
1601                 // distorted background
1602                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1603                 {
1604                         mode = SHADERMODE_WATER;
1605                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1606                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1607                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1608                         {
1609                                 // this is the right thing to do for wateralpha
1610                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1611                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1612                         }
1613                         else
1614                         {
1615                                 // this is the right thing to do for entity alpha
1616                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1617                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1618                         }
1619                 }
1620                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1621                 {
1622                         mode = SHADERMODE_REFRACTION;
1623                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1624                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1625                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1626                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                 }
1628                 else
1629                 {
1630                         mode = SHADERMODE_GENERIC;
1631                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1632                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1633                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1634                 }
1635                 if (vid.allowalphatocoverage)
1636                         GL_AlphaToCoverage(false);
1637         }
1638         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1639         {
1640                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1641                 {
1642                         switch(t->offsetmapping)
1643                         {
1644                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1645                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1646                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1647                         case OFFSETMAPPING_OFF: break;
1648                         }
1649                 }
1650                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1651                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1652                 // normalmap (deferred prepass), may use alpha test on diffuse
1653                 mode = SHADERMODE_DEFERREDGEOMETRY;
1654                 GL_BlendFunc(GL_ONE, GL_ZERO);
1655                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1656                 if (vid.allowalphatocoverage)
1657                         GL_AlphaToCoverage(false);
1658         }
1659         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1660         {
1661                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1662                 {
1663                         switch(t->offsetmapping)
1664                         {
1665                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1666                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1667                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1668                         case OFFSETMAPPING_OFF: break;
1669                         }
1670                 }
1671                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1672                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1673                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1674                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1675                 // light source
1676                 mode = SHADERMODE_LIGHTSOURCE;
1677                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1678                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1679                 if (VectorLength2(rtlightdiffuse) > 0)
1680                         permutation |= SHADERPERMUTATION_DIFFUSE;
1681                 if (VectorLength2(rtlightspecular) > 0)
1682                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1683                 if (r_refdef.fogenabled)
1684                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1685                 if (t->colormapping)
1686                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1687                 if (r_shadow_usingshadowmap2d)
1688                 {
1689                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1690                         if(r_shadow_shadowmapvsdct)
1691                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1692
1693                         if (r_shadow_shadowmap2ddepthbuffer)
1694                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1695                 }
1696                 if (t->reflectmasktexture)
1697                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1698                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1699                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1700                 if (vid.allowalphatocoverage)
1701                         GL_AlphaToCoverage(false);
1702         }
1703         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1704         {
1705                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1706                 {
1707                         switch(t->offsetmapping)
1708                         {
1709                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1710                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1711                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1712                         case OFFSETMAPPING_OFF: break;
1713                         }
1714                 }
1715                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1716                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1717                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1718                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1719                 // directional model lighting
1720                 mode = SHADERMODE_LIGHTGRID;
1721                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1722                         permutation |= SHADERPERMUTATION_GLOW;
1723                 permutation |= SHADERPERMUTATION_DIFFUSE;
1724                 if (t->glosstexture || t->backgroundglosstexture)
1725                         permutation |= SHADERPERMUTATION_SPECULAR;
1726                 if (r_refdef.fogenabled)
1727                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1728                 if (t->colormapping)
1729                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1730                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1731                 {
1732                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1733                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1734
1735                         if (r_shadow_shadowmap2ddepthbuffer)
1736                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1737                 }
1738                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1739                         permutation |= SHADERPERMUTATION_REFLECTION;
1740                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1741                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1742                 if (t->reflectmasktexture)
1743                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1744                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1745                 {
1746                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1747                         if (r_shadow_bouncegrid_state.directional)
1748                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1749                 }
1750                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1751                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1752                 // when using alphatocoverage, we don't need alphakill
1753                 if (vid.allowalphatocoverage)
1754                 {
1755                         if (r_transparent_alphatocoverage.integer)
1756                         {
1757                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1758                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1759                         }
1760                         else
1761                                 GL_AlphaToCoverage(false);
1762                 }
1763         }
1764         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1765         {
1766                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1767                 {
1768                         switch(t->offsetmapping)
1769                         {
1770                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1771                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1772                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1773                         case OFFSETMAPPING_OFF: break;
1774                         }
1775                 }
1776                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1777                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1778                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1779                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1780                 // directional model lighting
1781                 mode = SHADERMODE_LIGHTDIRECTION;
1782                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1783                         permutation |= SHADERPERMUTATION_GLOW;
1784                 if (VectorLength2(t->render_modellight_diffuse))
1785                         permutation |= SHADERPERMUTATION_DIFFUSE;
1786                 if (VectorLength2(t->render_modellight_specular) > 0)
1787                         permutation |= SHADERPERMUTATION_SPECULAR;
1788                 if (r_refdef.fogenabled)
1789                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1790                 if (t->colormapping)
1791                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1792                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1793                 {
1794                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1795                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1796
1797                         if (r_shadow_shadowmap2ddepthbuffer)
1798                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1799                 }
1800                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1801                         permutation |= SHADERPERMUTATION_REFLECTION;
1802                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1803                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1804                 if (t->reflectmasktexture)
1805                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1806                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1807                 {
1808                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1809                         if (r_shadow_bouncegrid_state.directional)
1810                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1811                 }
1812                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1813                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1814                 // when using alphatocoverage, we don't need alphakill
1815                 if (vid.allowalphatocoverage)
1816                 {
1817                         if (r_transparent_alphatocoverage.integer)
1818                         {
1819                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1820                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1821                         }
1822                         else
1823                                 GL_AlphaToCoverage(false);
1824                 }
1825         }
1826         else
1827         {
1828                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1829                 {
1830                         switch(t->offsetmapping)
1831                         {
1832                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1833                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1834                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1835                         case OFFSETMAPPING_OFF: break;
1836                         }
1837                 }
1838                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1839                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1840                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1841                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1842                 // lightmapped wall
1843                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1844                         permutation |= SHADERPERMUTATION_GLOW;
1845                 if (r_refdef.fogenabled)
1846                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1847                 if (t->colormapping)
1848                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1849                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1850                 {
1851                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1852                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1853
1854                         if (r_shadow_shadowmap2ddepthbuffer)
1855                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1856                 }
1857                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1858                         permutation |= SHADERPERMUTATION_REFLECTION;
1859                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1860                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1861                 if (t->reflectmasktexture)
1862                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1863                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1864                 {
1865                         // deluxemapping (light direction texture)
1866                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1867                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1868                         else
1869                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1870                         permutation |= SHADERPERMUTATION_DIFFUSE;
1871                         if (VectorLength2(t->render_lightmap_specular) > 0)
1872                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1873                 }
1874                 else if (r_glsl_deluxemapping.integer >= 2)
1875                 {
1876                         // fake deluxemapping (uniform light direction in tangentspace)
1877                         if (rsurface.uselightmaptexture)
1878                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1879                         else
1880                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1881                         permutation |= SHADERPERMUTATION_DIFFUSE;
1882                         if (VectorLength2(t->render_lightmap_specular) > 0)
1883                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1884                 }
1885                 else if (rsurface.uselightmaptexture)
1886                 {
1887                         // ordinary lightmapping (q1bsp, q3bsp)
1888                         mode = SHADERMODE_LIGHTMAP;
1889                 }
1890                 else
1891                 {
1892                         // ordinary vertex coloring (q3bsp)
1893                         mode = SHADERMODE_VERTEXCOLOR;
1894                 }
1895                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1896                 {
1897                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1898                         if (r_shadow_bouncegrid_state.directional)
1899                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1900                 }
1901                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1902                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1903                 // when using alphatocoverage, we don't need alphakill
1904                 if (vid.allowalphatocoverage)
1905                 {
1906                         if (r_transparent_alphatocoverage.integer)
1907                         {
1908                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1909                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1910                         }
1911                         else
1912                                 GL_AlphaToCoverage(false);
1913                 }
1914         }
1915         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1916                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1917         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !notrippy)
1918                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1919         switch(vid.renderpath)
1920         {
1921         case RENDERPATH_GL32:
1922         case RENDERPATH_GLES2:
1923                 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);
1924                 RSurf_UploadBuffersForBatch();
1925                 // this has to be after RSurf_PrepareVerticesForBatch
1926                 if (rsurface.batchskeletaltransform3x4buffer)
1927                         permutation |= SHADERPERMUTATION_SKELETAL;
1928                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1929 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1930                 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);
1931 #endif
1932                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1933                 if (mode == SHADERMODE_LIGHTSOURCE)
1934                 {
1935                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1936                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1937                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1938                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1939                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1940                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1941         
1942                         // additive passes are only darkened by fog, not tinted
1943                         if (r_glsl_permutation->loc_FogColor >= 0)
1944                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1945                         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);
1946                 }
1947                 else
1948                 {
1949                         if (mode == SHADERMODE_FLATCOLOR)
1950                         {
1951                                 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]);
1952                         }
1953                         else if (mode == SHADERMODE_LIGHTGRID)
1954                         {
1955                                 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]);
1956                                 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]);
1957                                 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]);
1958                                 // other LightGrid uniforms handled below
1959                         }
1960                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1961                         {
1962                                 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]);
1963                                 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]);
1964                                 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]);
1965                                 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]);
1966                                 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]);
1967                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1968                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1969                         }
1970                         else
1971                         {
1972                                 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]);
1973                                 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]);
1974                                 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]);
1975                                 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]);
1976                                 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]);
1977                         }
1978                         // additive passes are only darkened by fog, not tinted
1979                         if (r_glsl_permutation->loc_FogColor >= 0 && !notrippy)
1980                         {
1981                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1982                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1983                                 else
1984                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1985                         }
1986                         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);
1987                         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]);
1988                         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]);
1989                         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);
1990                         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);
1991                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1992                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1993                         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);
1994                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1995                 }
1996                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1997                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1998                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1999                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
2000                 {
2001                         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]);
2002                         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]);
2003                 }
2004                 else
2005                 {
2006                         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]);
2007                         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]);
2008                 }
2009
2010                 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]);
2011                 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));
2012                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2013                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2014                 {
2015                         if (t->pantstexture)
2016                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2017                         else
2018                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2019                 }
2020                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2021                 {
2022                         if (t->shirttexture)
2023                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2024                         else
2025                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2026                 }
2027                 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]);
2028                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2029                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2030                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2031                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2032                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2033                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2034                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2035                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2036                         );
2037                 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);
2038                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2039                 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]);
2040                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2041                 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);}
2042                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2043                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2044                 {
2045                         float m9f[9];
2046                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2047                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2048                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2049                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2050                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2051                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2052                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2053                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2054                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2055                 }
2056
2057                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2058                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2059                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2060                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2061                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2062                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2063                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2064                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2065                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2066                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2067                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2068                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2069                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2070                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2071                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2072                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2073                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2074                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2075                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2076                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2077                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2078                 {
2079                         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);
2080                         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);
2081                         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);
2082                 }
2083                 else
2084                 {
2085                         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);
2086                 }
2087                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2088                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2089                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2090                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2091                 {
2092                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2093                         if (rsurface.rtlight)
2094                         {
2095                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2096                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2097                         }
2098                 }
2099                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2100                 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);
2101                 CHECKGLERROR
2102                 break;
2103         }
2104 }
2105
2106 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2107 {
2108         // select a permutation of the lighting shader appropriate to this
2109         // combination of texture, entity, light source, and fogging, only use the
2110         // minimum features necessary to avoid wasting rendering time in the
2111         // fragment shader on features that are not being used
2112         uint64_t permutation = 0;
2113         unsigned int mode = 0;
2114         const float *lightcolorbase = rtlight->currentcolor;
2115         float ambientscale = rtlight->ambientscale;
2116         float diffusescale = rtlight->diffusescale;
2117         float specularscale = rtlight->specularscale;
2118         // this is the location of the light in view space
2119         vec3_t viewlightorigin;
2120         // this transforms from view space (camera) to light space (cubemap)
2121         matrix4x4_t viewtolight;
2122         matrix4x4_t lighttoview;
2123         float viewtolight16f[16];
2124         // light source
2125         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2126         if (rtlight->currentcubemap != r_texture_whitecube)
2127                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2128         if (diffusescale > 0)
2129                 permutation |= SHADERPERMUTATION_DIFFUSE;
2130         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2131                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2132         if (r_shadow_usingshadowmap2d)
2133         {
2134                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2135                 if (r_shadow_shadowmapvsdct)
2136                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2137
2138                 if (r_shadow_shadowmap2ddepthbuffer)
2139                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2140         }
2141         if (vid.allowalphatocoverage)
2142                 GL_AlphaToCoverage(false);
2143         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2144         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2145         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2146         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2147         switch(vid.renderpath)
2148         {
2149         case RENDERPATH_GL32:
2150         case RENDERPATH_GLES2:
2151                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2152                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2153                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2154                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2155                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2156                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2157                 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]);
2158                 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]);
2159                 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);
2160                 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]);
2161                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2162
2163                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2164                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2165                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2166                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2167                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2168                 break;
2169         }
2170 }
2171
2172 #define SKINFRAME_HASH 1024
2173
2174 typedef struct
2175 {
2176         unsigned int loadsequence; // incremented each level change
2177         memexpandablearray_t array;
2178         skinframe_t *hash[SKINFRAME_HASH];
2179 }
2180 r_skinframe_t;
2181 r_skinframe_t r_skinframe;
2182
2183 void R_SkinFrame_PrepareForPurge(void)
2184 {
2185         r_skinframe.loadsequence++;
2186         // wrap it without hitting zero
2187         if (r_skinframe.loadsequence >= 200)
2188                 r_skinframe.loadsequence = 1;
2189 }
2190
2191 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2192 {
2193         if (!skinframe)
2194                 return;
2195         // mark the skinframe as used for the purging code
2196         skinframe->loadsequence = r_skinframe.loadsequence;
2197 }
2198
2199 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2200 {
2201         if (s == NULL)
2202                 return;
2203         if (s->merged == s->base)
2204                 s->merged = NULL;
2205         R_PurgeTexture(s->stain); s->stain = NULL;
2206         R_PurgeTexture(s->merged); s->merged = NULL;
2207         R_PurgeTexture(s->base); s->base = NULL;
2208         R_PurgeTexture(s->pants); s->pants = NULL;
2209         R_PurgeTexture(s->shirt); s->shirt = NULL;
2210         R_PurgeTexture(s->nmap); s->nmap = NULL;
2211         R_PurgeTexture(s->gloss); s->gloss = NULL;
2212         R_PurgeTexture(s->glow); s->glow = NULL;
2213         R_PurgeTexture(s->fog); s->fog = NULL;
2214         R_PurgeTexture(s->reflect); s->reflect = NULL;
2215         s->loadsequence = 0;
2216 }
2217
2218 void R_SkinFrame_Purge(void)
2219 {
2220         int i;
2221         skinframe_t *s;
2222         for (i = 0;i < SKINFRAME_HASH;i++)
2223         {
2224                 for (s = r_skinframe.hash[i];s;s = s->next)
2225                 {
2226                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2227                                 R_SkinFrame_PurgeSkinFrame(s);
2228                 }
2229         }
2230 }
2231
2232 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2233         skinframe_t *item;
2234         char basename[MAX_QPATH];
2235
2236         Image_StripImageExtension(name, basename, sizeof(basename));
2237
2238         if( last == NULL ) {
2239                 int hashindex;
2240                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2241                 item = r_skinframe.hash[hashindex];
2242         } else {
2243                 item = last->next;
2244         }
2245
2246         // linearly search through the hash bucket
2247         for( ; item ; item = item->next ) {
2248                 if( !strcmp( item->basename, basename ) ) {
2249                         return item;
2250                 }
2251         }
2252         return NULL;
2253 }
2254
2255 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2256 {
2257         skinframe_t *item;
2258         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2259         int hashindex;
2260         char basename[MAX_QPATH];
2261
2262         Image_StripImageExtension(name, basename, sizeof(basename));
2263
2264         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2265         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2266                 if (!strcmp(item->basename, basename) &&
2267                         item->textureflags == compareflags &&
2268                         item->comparewidth == comparewidth &&
2269                         item->compareheight == compareheight &&
2270                         item->comparecrc == comparecrc)
2271                         break;
2272
2273         if (!item)
2274         {
2275                 if (!add)
2276                         return NULL;
2277                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2278                 memset(item, 0, sizeof(*item));
2279                 strlcpy(item->basename, basename, sizeof(item->basename));
2280                 item->textureflags = compareflags;
2281                 item->comparewidth = comparewidth;
2282                 item->compareheight = compareheight;
2283                 item->comparecrc = comparecrc;
2284                 item->next = r_skinframe.hash[hashindex];
2285                 r_skinframe.hash[hashindex] = item;
2286         }
2287         else if (textureflags & TEXF_FORCE_RELOAD)
2288                 R_SkinFrame_PurgeSkinFrame(item);
2289
2290         R_SkinFrame_MarkUsed(item);
2291         return item;
2292 }
2293
2294 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2295         { \
2296                 unsigned long long avgcolor[5], wsum; \
2297                 int pix, comp, w; \
2298                 avgcolor[0] = 0; \
2299                 avgcolor[1] = 0; \
2300                 avgcolor[2] = 0; \
2301                 avgcolor[3] = 0; \
2302                 avgcolor[4] = 0; \
2303                 wsum = 0; \
2304                 for(pix = 0; pix < cnt; ++pix) \
2305                 { \
2306                         w = 0; \
2307                         for(comp = 0; comp < 3; ++comp) \
2308                                 w += getpixel; \
2309                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2310                         { \
2311                                 ++wsum; \
2312                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2313                                 w = getpixel; \
2314                                 for(comp = 0; comp < 3; ++comp) \
2315                                         avgcolor[comp] += getpixel * w; \
2316                                 avgcolor[3] += w; \
2317                         } \
2318                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2319                         avgcolor[4] += getpixel; \
2320                 } \
2321                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2322                         avgcolor[3] = 1; \
2323                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2324                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2325                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2326                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2327         }
2328
2329 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2330 {
2331         skinframe_t *skinframe;
2332
2333         if (cls.state == ca_dedicated)
2334                 return NULL;
2335
2336         // return an existing skinframe if already loaded
2337         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2338         if (skinframe && skinframe->base)
2339                 return skinframe;
2340
2341         // if the skinframe doesn't exist this will create it
2342         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2343 }
2344
2345 extern cvar_t gl_picmip;
2346 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2347 {
2348         int j;
2349         unsigned char *pixels;
2350         unsigned char *bumppixels;
2351         unsigned char *basepixels = NULL;
2352         int basepixels_width = 0;
2353         int basepixels_height = 0;
2354         rtexture_t *ddsbase = NULL;
2355         qboolean ddshasalpha = false;
2356         float ddsavgcolor[4];
2357         char basename[MAX_QPATH];
2358         int miplevel = R_PicmipForFlags(textureflags);
2359         int savemiplevel = miplevel;
2360         int mymiplevel;
2361         char vabuf[1024];
2362
2363         if (cls.state == ca_dedicated)
2364                 return NULL;
2365
2366         Image_StripImageExtension(name, basename, sizeof(basename));
2367
2368         // check for DDS texture file first
2369         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2370         {
2371                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2372                 if (basepixels == NULL && fallbacknotexture)
2373                         basepixels = Image_GenerateNoTexture();
2374                 if (basepixels == NULL)
2375                         return NULL;
2376         }
2377
2378         // FIXME handle miplevel
2379
2380         if (developer_loading.integer)
2381                 Con_Printf("loading skin \"%s\"\n", name);
2382
2383         // we've got some pixels to store, so really allocate this new texture now
2384         if (!skinframe)
2385                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2386         textureflags &= ~TEXF_FORCE_RELOAD;
2387         skinframe->stain = NULL;
2388         skinframe->merged = NULL;
2389         skinframe->base = NULL;
2390         skinframe->pants = NULL;
2391         skinframe->shirt = NULL;
2392         skinframe->nmap = NULL;
2393         skinframe->gloss = NULL;
2394         skinframe->glow = NULL;
2395         skinframe->fog = NULL;
2396         skinframe->reflect = NULL;
2397         skinframe->hasalpha = false;
2398         // we could store the q2animname here too
2399
2400         if (ddsbase)
2401         {
2402                 skinframe->base = ddsbase;
2403                 skinframe->hasalpha = ddshasalpha;
2404                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2405                 if (r_loadfog && skinframe->hasalpha)
2406                         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);
2407                 //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]);
2408         }
2409         else
2410         {
2411                 basepixels_width = image_width;
2412                 basepixels_height = image_height;
2413                 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);
2414                 if (textureflags & TEXF_ALPHA)
2415                 {
2416                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2417                         {
2418                                 if (basepixels[j] < 255)
2419                                 {
2420                                         skinframe->hasalpha = true;
2421                                         break;
2422                                 }
2423                         }
2424                         if (r_loadfog && skinframe->hasalpha)
2425                         {
2426                                 // has transparent pixels
2427                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2428                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2429                                 {
2430                                         pixels[j+0] = 255;
2431                                         pixels[j+1] = 255;
2432                                         pixels[j+2] = 255;
2433                                         pixels[j+3] = basepixels[j+3];
2434                                 }
2435                                 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);
2436                                 Mem_Free(pixels);
2437                         }
2438                 }
2439                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2440 #ifndef USE_GLES2
2441                 //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]);
2442                 if (r_savedds && skinframe->base)
2443                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2444                 if (r_savedds && skinframe->fog)
2445                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2446 #endif
2447         }
2448
2449         if (r_loaddds)
2450         {
2451                 mymiplevel = savemiplevel;
2452                 if (r_loadnormalmap)
2453                         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);
2454                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2455                 if (r_loadgloss)
2456                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2457                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2458                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2459                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2460         }
2461
2462         // _norm is the name used by tenebrae and has been adopted as standard
2463         if (r_loadnormalmap && skinframe->nmap == NULL)
2464         {
2465                 mymiplevel = savemiplevel;
2466                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2467                 {
2468                         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);
2469                         Mem_Free(pixels);
2470                         pixels = NULL;
2471                 }
2472                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2473                 {
2474                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2475                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2476                         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);
2477                         Mem_Free(pixels);
2478                         Mem_Free(bumppixels);
2479                 }
2480                 else if (r_shadow_bumpscale_basetexture.value > 0)
2481                 {
2482                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2483                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2484                         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);
2485                         Mem_Free(pixels);
2486                 }
2487 #ifndef USE_GLES2
2488                 if (r_savedds && skinframe->nmap)
2489                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2490 #endif
2491         }
2492
2493         // _luma is supported only for tenebrae compatibility
2494         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2495         // _glow is the preferred name
2496         mymiplevel = savemiplevel;
2497         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))))
2498         {
2499                 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);
2500 #ifndef USE_GLES2
2501                 if (r_savedds && skinframe->glow)
2502                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2503 #endif
2504                 Mem_Free(pixels);pixels = NULL;
2505         }
2506
2507         mymiplevel = savemiplevel;
2508         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2509         {
2510                 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);
2511 #ifndef USE_GLES2
2512                 if (r_savedds && skinframe->gloss)
2513                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2514 #endif
2515                 Mem_Free(pixels);
2516                 pixels = NULL;
2517         }
2518
2519         mymiplevel = savemiplevel;
2520         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2521         {
2522                 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);
2523 #ifndef USE_GLES2
2524                 if (r_savedds && skinframe->pants)
2525                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2526 #endif
2527                 Mem_Free(pixels);
2528                 pixels = NULL;
2529         }
2530
2531         mymiplevel = savemiplevel;
2532         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2533         {
2534                 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);
2535 #ifndef USE_GLES2
2536                 if (r_savedds && skinframe->shirt)
2537                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2538 #endif
2539                 Mem_Free(pixels);
2540                 pixels = NULL;
2541         }
2542
2543         mymiplevel = savemiplevel;
2544         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2545         {
2546                 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);
2547 #ifndef USE_GLES2
2548                 if (r_savedds && skinframe->reflect)
2549                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2550 #endif
2551                 Mem_Free(pixels);
2552                 pixels = NULL;
2553         }
2554
2555         if (basepixels)
2556                 Mem_Free(basepixels);
2557
2558         return skinframe;
2559 }
2560
2561 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qboolean sRGB)
2562 {
2563         int i;
2564         skinframe_t *skinframe;
2565         char vabuf[1024];
2566
2567         if (cls.state == ca_dedicated)
2568                 return NULL;
2569
2570         // if already loaded just return it, otherwise make a new skinframe
2571         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2572         if (skinframe->base)
2573                 return skinframe;
2574         textureflags &= ~TEXF_FORCE_RELOAD;
2575
2576         skinframe->stain = NULL;
2577         skinframe->merged = NULL;
2578         skinframe->base = NULL;
2579         skinframe->pants = NULL;
2580         skinframe->shirt = NULL;
2581         skinframe->nmap = NULL;
2582         skinframe->gloss = NULL;
2583         skinframe->glow = NULL;
2584         skinframe->fog = NULL;
2585         skinframe->reflect = NULL;
2586         skinframe->hasalpha = false;
2587
2588         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2589         if (!skindata)
2590                 return NULL;
2591
2592         if (developer_loading.integer)
2593                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2594
2595         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2596         {
2597                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2598                 unsigned char *b = a + width * height * 4;
2599                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2600                 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);
2601                 Mem_Free(a);
2602         }
2603         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2604         if (textureflags & TEXF_ALPHA)
2605         {
2606                 for (i = 3;i < width * height * 4;i += 4)
2607                 {
2608                         if (skindata[i] < 255)
2609                         {
2610                                 skinframe->hasalpha = true;
2611                                 break;
2612                         }
2613                 }
2614                 if (r_loadfog && skinframe->hasalpha)
2615                 {
2616                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2617                         memcpy(fogpixels, skindata, width * height * 4);
2618                         for (i = 0;i < width * height * 4;i += 4)
2619                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2620                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2621                         Mem_Free(fogpixels);
2622                 }
2623         }
2624
2625         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2626         //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]);
2627
2628         return skinframe;
2629 }
2630
2631 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2632 {
2633         int i;
2634         int featuresmask;
2635         skinframe_t *skinframe;
2636
2637         if (cls.state == ca_dedicated)
2638                 return NULL;
2639
2640         // if already loaded just return it, otherwise make a new skinframe
2641         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2642         if (skinframe->base)
2643                 return skinframe;
2644         //textureflags &= ~TEXF_FORCE_RELOAD;
2645
2646         skinframe->stain = NULL;
2647         skinframe->merged = NULL;
2648         skinframe->base = NULL;
2649         skinframe->pants = NULL;
2650         skinframe->shirt = NULL;
2651         skinframe->nmap = NULL;
2652         skinframe->gloss = NULL;
2653         skinframe->glow = NULL;
2654         skinframe->fog = NULL;
2655         skinframe->reflect = NULL;
2656         skinframe->hasalpha = false;
2657
2658         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2659         if (!skindata)
2660                 return NULL;
2661
2662         if (developer_loading.integer)
2663                 Con_Printf("loading quake skin \"%s\"\n", name);
2664
2665         // 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)
2666         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2667         memcpy(skinframe->qpixels, skindata, width*height);
2668         skinframe->qwidth = width;
2669         skinframe->qheight = height;
2670
2671         featuresmask = 0;
2672         for (i = 0;i < width * height;i++)
2673                 featuresmask |= palette_featureflags[skindata[i]];
2674
2675         skinframe->hasalpha = false;
2676         // fence textures
2677         if (name[0] == '{')
2678                 skinframe->hasalpha = true;
2679         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2680         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2681         skinframe->qgeneratemerged = true;
2682         skinframe->qgeneratebase = skinframe->qhascolormapping;
2683         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2684
2685         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2686         //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]);
2687
2688         return skinframe;
2689 }
2690
2691 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2692 {
2693         int width;
2694         int height;
2695         unsigned char *skindata;
2696         char vabuf[1024];
2697
2698         if (!skinframe->qpixels)
2699                 return;
2700
2701         if (!skinframe->qhascolormapping)
2702                 colormapped = false;
2703
2704         if (colormapped)
2705         {
2706                 if (!skinframe->qgeneratebase)
2707                         return;
2708         }
2709         else
2710         {
2711                 if (!skinframe->qgeneratemerged)
2712                         return;
2713         }
2714
2715         width = skinframe->qwidth;
2716         height = skinframe->qheight;
2717         skindata = skinframe->qpixels;
2718
2719         if (skinframe->qgeneratenmap)
2720         {
2721                 unsigned char *a, *b;
2722                 skinframe->qgeneratenmap = false;
2723                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2724                 b = a + width * height * 4;
2725                 // use either a custom palette or the quake palette
2726                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2727                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2728                 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);
2729                 Mem_Free(a);
2730         }
2731
2732         if (skinframe->qgenerateglow)
2733         {
2734                 skinframe->qgenerateglow = false;
2735                 if (skinframe->hasalpha) // fence textures
2736                         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
2737                 else
2738                         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
2739         }
2740
2741         if (colormapped)
2742         {
2743                 skinframe->qgeneratebase = false;
2744                 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);
2745                 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);
2746                 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);
2747         }
2748         else
2749         {
2750                 skinframe->qgeneratemerged = false;
2751                 if (skinframe->hasalpha) // fence textures
2752                         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);
2753                 else
2754                         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);
2755         }
2756
2757         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2758         {
2759                 Mem_Free(skinframe->qpixels);
2760                 skinframe->qpixels = NULL;
2761         }
2762 }
2763
2764 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)
2765 {
2766         int i;
2767         skinframe_t *skinframe;
2768         char vabuf[1024];
2769
2770         if (cls.state == ca_dedicated)
2771                 return NULL;
2772
2773         // if already loaded just return it, otherwise make a new skinframe
2774         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2775         if (skinframe->base)
2776                 return skinframe;
2777         textureflags &= ~TEXF_FORCE_RELOAD;
2778
2779         skinframe->stain = NULL;
2780         skinframe->merged = NULL;
2781         skinframe->base = NULL;
2782         skinframe->pants = NULL;
2783         skinframe->shirt = NULL;
2784         skinframe->nmap = NULL;
2785         skinframe->gloss = NULL;
2786         skinframe->glow = NULL;
2787         skinframe->fog = NULL;
2788         skinframe->reflect = NULL;
2789         skinframe->hasalpha = false;
2790
2791         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2792         if (!skindata)
2793                 return NULL;
2794
2795         if (developer_loading.integer)
2796                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2797
2798         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2799         if ((textureflags & TEXF_ALPHA) && alphapalette)
2800         {
2801                 for (i = 0;i < width * height;i++)
2802                 {
2803                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2804                         {
2805                                 skinframe->hasalpha = true;
2806                                 break;
2807                         }
2808                 }
2809                 if (r_loadfog && skinframe->hasalpha)
2810                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2811         }
2812
2813         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2814         //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]);
2815
2816         return skinframe;
2817 }
2818
2819 skinframe_t *R_SkinFrame_LoadMissing(void)
2820 {
2821         skinframe_t *skinframe;
2822
2823         if (cls.state == ca_dedicated)
2824                 return NULL;
2825
2826         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2827         skinframe->stain = NULL;
2828         skinframe->merged = NULL;
2829         skinframe->base = NULL;
2830         skinframe->pants = NULL;
2831         skinframe->shirt = NULL;
2832         skinframe->nmap = NULL;
2833         skinframe->gloss = NULL;
2834         skinframe->glow = NULL;
2835         skinframe->fog = NULL;
2836         skinframe->reflect = NULL;
2837         skinframe->hasalpha = false;
2838
2839         skinframe->avgcolor[0] = rand() / RAND_MAX;
2840         skinframe->avgcolor[1] = rand() / RAND_MAX;
2841         skinframe->avgcolor[2] = rand() / RAND_MAX;
2842         skinframe->avgcolor[3] = 1;
2843
2844         return skinframe;
2845 }
2846
2847 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2848 {
2849         int x, y;
2850         static unsigned char pix[16][16][4];
2851
2852         if (cls.state == ca_dedicated)
2853                 return NULL;
2854
2855         // this makes a light grey/dark grey checkerboard texture
2856         if (!pix[0][0][3])
2857         {
2858                 for (y = 0; y < 16; y++)
2859                 {
2860                         for (x = 0; x < 16; x++)
2861                         {
2862                                 if ((y < 8) ^ (x < 8))
2863                                 {
2864                                         pix[y][x][0] = 128;
2865                                         pix[y][x][1] = 128;
2866                                         pix[y][x][2] = 128;
2867                                         pix[y][x][3] = 255;
2868                                 }
2869                                 else
2870                                 {
2871                                         pix[y][x][0] = 64;
2872                                         pix[y][x][1] = 64;
2873                                         pix[y][x][2] = 64;
2874                                         pix[y][x][3] = 255;
2875                                 }
2876                         }
2877                 }
2878         }
2879
2880         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2881 }
2882
2883 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2884 {
2885         skinframe_t *skinframe;
2886         if (cls.state == ca_dedicated)
2887                 return NULL;
2888         // if already loaded just return it, otherwise make a new skinframe
2889         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2890         if (skinframe->base)
2891                 return skinframe;
2892         textureflags &= ~TEXF_FORCE_RELOAD;
2893         skinframe->stain = NULL;
2894         skinframe->merged = NULL;
2895         skinframe->base = NULL;
2896         skinframe->pants = NULL;
2897         skinframe->shirt = NULL;
2898         skinframe->nmap = NULL;
2899         skinframe->gloss = NULL;
2900         skinframe->glow = NULL;
2901         skinframe->fog = NULL;
2902         skinframe->reflect = NULL;
2903         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2904         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2905         if (!tex)
2906                 return NULL;
2907         if (developer_loading.integer)
2908                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2909         skinframe->base = skinframe->merged = tex;
2910         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2911         return skinframe;
2912 }
2913
2914 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2915 typedef struct suffixinfo_s
2916 {
2917         const char *suffix;
2918         qboolean flipx, flipy, flipdiagonal;
2919 }
2920 suffixinfo_t;
2921 static suffixinfo_t suffix[3][6] =
2922 {
2923         {
2924                 {"px",   false, false, false},
2925                 {"nx",   false, false, false},
2926                 {"py",   false, false, false},
2927                 {"ny",   false, false, false},
2928                 {"pz",   false, false, false},
2929                 {"nz",   false, false, false}
2930         },
2931         {
2932                 {"posx", false, false, false},
2933                 {"negx", false, false, false},
2934                 {"posy", false, false, false},
2935                 {"negy", false, false, false},
2936                 {"posz", false, false, false},
2937                 {"negz", false, false, false}
2938         },
2939         {
2940                 {"rt",    true, false,  true},
2941                 {"lf",   false,  true,  true},
2942                 {"ft",    true,  true, false},
2943                 {"bk",   false, false, false},
2944                 {"up",    true, false,  true},
2945                 {"dn",    true, false,  true}
2946         }
2947 };
2948
2949 static int componentorder[4] = {0, 1, 2, 3};
2950
2951 static rtexture_t *R_LoadCubemap(const char *basename)
2952 {
2953         int i, j, cubemapsize, forcefilter;
2954         unsigned char *cubemappixels, *image_buffer;
2955         rtexture_t *cubemaptexture;
2956         char name[256];
2957
2958         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2959         forcefilter = TEXF_FORCELINEAR;
2960         if (basename && basename[0] == '!')
2961         {
2962                 basename++;
2963                 forcefilter = TEXF_FORCENEAREST;
2964         }
2965         // must start 0 so the first loadimagepixels has no requested width/height
2966         cubemapsize = 0;
2967         cubemappixels = NULL;
2968         cubemaptexture = NULL;
2969         // keep trying different suffix groups (posx, px, rt) until one loads
2970         for (j = 0;j < 3 && !cubemappixels;j++)
2971         {
2972                 // load the 6 images in the suffix group
2973                 for (i = 0;i < 6;i++)
2974                 {
2975                         // generate an image name based on the base and and suffix
2976                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2977                         // load it
2978                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2979                         {
2980                                 // an image loaded, make sure width and height are equal
2981                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2982                                 {
2983                                         // if this is the first image to load successfully, allocate the cubemap memory
2984                                         if (!cubemappixels && image_width >= 1)
2985                                         {
2986                                                 cubemapsize = image_width;
2987                                                 // note this clears to black, so unavailable sides are black
2988                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2989                                         }
2990                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2991                                         if (cubemappixels)
2992                                                 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);
2993                                 }
2994                                 else
2995                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2996                                 // free the image
2997                                 Mem_Free(image_buffer);
2998                         }
2999                 }
3000         }
3001         // if a cubemap loaded, upload it
3002         if (cubemappixels)
3003         {
3004                 if (developer_loading.integer)
3005                         Con_Printf("loading cubemap \"%s\"\n", basename);
3006
3007                 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);
3008                 Mem_Free(cubemappixels);
3009         }
3010         else
3011         {
3012                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3013                 if (developer_loading.integer)
3014                 {
3015                         Con_Printf("(tried tried images ");
3016                         for (j = 0;j < 3;j++)
3017                                 for (i = 0;i < 6;i++)
3018                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3019                         Con_Print(" and was unable to find any of them).\n");
3020                 }
3021         }
3022         return cubemaptexture;
3023 }
3024
3025 rtexture_t *R_GetCubemap(const char *basename)
3026 {
3027         int i;
3028         for (i = 0;i < r_texture_numcubemaps;i++)
3029                 if (r_texture_cubemaps[i] != NULL)
3030                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
3031                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
3032         if (i >= MAX_CUBEMAPS || !r_main_mempool)
3033                 return r_texture_whitecube;
3034         r_texture_numcubemaps++;
3035         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
3036         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
3037         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
3038         return r_texture_cubemaps[i]->texture;
3039 }
3040
3041 static void R_Main_FreeViewCache(void)
3042 {
3043         if (r_refdef.viewcache.entityvisible)
3044                 Mem_Free(r_refdef.viewcache.entityvisible);
3045         if (r_refdef.viewcache.world_pvsbits)
3046                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3047         if (r_refdef.viewcache.world_leafvisible)
3048                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3049         if (r_refdef.viewcache.world_surfacevisible)
3050                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3051         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3052 }
3053
3054 static void R_Main_ResizeViewCache(void)
3055 {
3056         int numentities = r_refdef.scene.numentities;
3057         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3058         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3059         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3060         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3061         if (r_refdef.viewcache.maxentities < numentities)
3062         {
3063                 r_refdef.viewcache.maxentities = numentities;
3064                 if (r_refdef.viewcache.entityvisible)
3065                         Mem_Free(r_refdef.viewcache.entityvisible);
3066                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3067         }
3068         if (r_refdef.viewcache.world_numclusters != numclusters)
3069         {
3070                 r_refdef.viewcache.world_numclusters = numclusters;
3071                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3072                 if (r_refdef.viewcache.world_pvsbits)
3073                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3074                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3075         }
3076         if (r_refdef.viewcache.world_numleafs != numleafs)
3077         {
3078                 r_refdef.viewcache.world_numleafs = numleafs;
3079                 if (r_refdef.viewcache.world_leafvisible)
3080                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3081                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3082         }
3083         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3084         {
3085                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3086                 if (r_refdef.viewcache.world_surfacevisible)
3087                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3088                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3089         }
3090 }
3091
3092 extern rtexture_t *loadingscreentexture;
3093 static void gl_main_start(void)
3094 {
3095         loadingscreentexture = NULL;
3096         r_texture_blanknormalmap = NULL;
3097         r_texture_white = NULL;
3098         r_texture_grey128 = NULL;
3099         r_texture_black = NULL;
3100         r_texture_whitecube = NULL;
3101         r_texture_normalizationcube = NULL;
3102         r_texture_fogattenuation = NULL;
3103         r_texture_fogheighttexture = NULL;
3104         r_texture_gammaramps = NULL;
3105         r_texture_numcubemaps = 0;
3106         r_uniformbufferalignment = 32;
3107
3108         r_loaddds = r_texture_dds_load.integer != 0;
3109         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3110
3111         switch(vid.renderpath)
3112         {
3113         case RENDERPATH_GL32:
3114         case RENDERPATH_GLES2:
3115                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3116                 Cvar_SetValueQuick(&gl_combine, 1);
3117                 Cvar_SetValueQuick(&r_glsl, 1);
3118                 r_loadnormalmap = true;
3119                 r_loadgloss = true;
3120                 r_loadfog = false;
3121 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3122                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3123 #endif
3124                 break;
3125         }
3126
3127         R_AnimCache_Free();
3128         R_FrameData_Reset();
3129         R_BufferData_Reset();
3130
3131         r_numqueries = 0;
3132         r_maxqueries = 0;
3133         memset(r_queries, 0, sizeof(r_queries));
3134
3135         r_qwskincache = NULL;
3136         r_qwskincache_size = 0;
3137
3138         // due to caching of texture_t references, the collision cache must be reset
3139         Collision_Cache_Reset(true);
3140
3141         // set up r_skinframe loading system for textures
3142         memset(&r_skinframe, 0, sizeof(r_skinframe));
3143         r_skinframe.loadsequence = 1;
3144         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3145
3146         r_main_texturepool = R_AllocTexturePool();
3147         R_BuildBlankTextures();
3148         R_BuildNoTexture();
3149         R_BuildWhiteCube();
3150         R_BuildNormalizationCube();
3151         r_texture_fogattenuation = NULL;
3152         r_texture_fogheighttexture = NULL;
3153         r_texture_gammaramps = NULL;
3154         //r_texture_fogintensity = NULL;
3155         memset(&r_fb, 0, sizeof(r_fb));
3156         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3157         r_glsl_permutation = NULL;
3158         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3159         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3160         memset(&r_svbsp, 0, sizeof (r_svbsp));
3161
3162         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3163         r_texture_numcubemaps = 0;
3164
3165         r_refdef.fogmasktable_density = 0;
3166
3167 #ifdef __ANDROID__
3168         // For Steelstorm Android
3169         // FIXME CACHE the program and reload
3170         // FIXME see possible combinations for SS:BR android
3171         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3172         R_SetupShader_SetPermutationGLSL(0, 12);
3173         R_SetupShader_SetPermutationGLSL(0, 13);
3174         R_SetupShader_SetPermutationGLSL(0, 8388621);
3175         R_SetupShader_SetPermutationGLSL(3, 0);
3176         R_SetupShader_SetPermutationGLSL(3, 2048);
3177         R_SetupShader_SetPermutationGLSL(5, 0);
3178         R_SetupShader_SetPermutationGLSL(5, 2);
3179         R_SetupShader_SetPermutationGLSL(5, 2048);
3180         R_SetupShader_SetPermutationGLSL(5, 8388608);
3181         R_SetupShader_SetPermutationGLSL(11, 1);
3182         R_SetupShader_SetPermutationGLSL(11, 2049);
3183         R_SetupShader_SetPermutationGLSL(11, 8193);
3184         R_SetupShader_SetPermutationGLSL(11, 10241);
3185         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3186 #endif
3187 }
3188
3189 extern unsigned int r_shadow_occlusion_buf;
3190
3191 static void gl_main_shutdown(void)
3192 {
3193         R_RenderTarget_FreeUnused(true);
3194         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3195         R_AnimCache_Free();
3196         R_FrameData_Reset();
3197         R_BufferData_Reset();
3198
3199         R_Main_FreeViewCache();
3200
3201         switch(vid.renderpath)
3202         {
3203         case RENDERPATH_GL32:
3204         case RENDERPATH_GLES2:
3205 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3206                 if (r_maxqueries)
3207                         qglDeleteQueries(r_maxqueries, r_queries);
3208 #endif
3209                 break;
3210         }
3211         r_shadow_occlusion_buf = 0;
3212         r_numqueries = 0;
3213         r_maxqueries = 0;
3214         memset(r_queries, 0, sizeof(r_queries));
3215
3216         r_qwskincache = NULL;
3217         r_qwskincache_size = 0;
3218
3219         // clear out the r_skinframe state
3220         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3221         memset(&r_skinframe, 0, sizeof(r_skinframe));
3222
3223         if (r_svbsp.nodes)
3224                 Mem_Free(r_svbsp.nodes);
3225         memset(&r_svbsp, 0, sizeof (r_svbsp));
3226         R_FreeTexturePool(&r_main_texturepool);
3227         loadingscreentexture = NULL;
3228         r_texture_blanknormalmap = NULL;
3229         r_texture_white = NULL;
3230         r_texture_grey128 = NULL;
3231         r_texture_black = NULL;
3232         r_texture_whitecube = NULL;
3233         r_texture_normalizationcube = NULL;
3234         r_texture_fogattenuation = NULL;
3235         r_texture_fogheighttexture = NULL;
3236         r_texture_gammaramps = NULL;
3237         r_texture_numcubemaps = 0;
3238         //r_texture_fogintensity = NULL;
3239         memset(&r_fb, 0, sizeof(r_fb));
3240         R_GLSL_Restart_f(&cmd_client);
3241
3242         r_glsl_permutation = NULL;
3243         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3244         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3245 }
3246
3247 static void gl_main_newmap(void)
3248 {
3249         // FIXME: move this code to client
3250         char *entities, entname[MAX_QPATH];
3251         if (r_qwskincache)
3252                 Mem_Free(r_qwskincache);
3253         r_qwskincache = NULL;
3254         r_qwskincache_size = 0;
3255         if (cl.worldmodel)
3256         {
3257                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3258                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3259                 {
3260                         CL_ParseEntityLump(entities);
3261                         Mem_Free(entities);
3262                         return;
3263                 }
3264                 if (cl.worldmodel->brush.entities)
3265                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3266         }
3267         R_Main_FreeViewCache();
3268
3269         R_FrameData_Reset();
3270         R_BufferData_Reset();
3271 }
3272
3273 void GL_Main_Init(void)
3274 {
3275         int i;
3276         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3277         R_InitShaderModeInfo();
3278
3279         Cmd_AddCommand(CMD_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3280         Cmd_AddCommand(CMD_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3281         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3282         if (gamemode == GAME_NEHAHRA)
3283         {
3284                 Cvar_RegisterVariable (&gl_fogenable);
3285                 Cvar_RegisterVariable (&gl_fogdensity);
3286                 Cvar_RegisterVariable (&gl_fogred);
3287                 Cvar_RegisterVariable (&gl_foggreen);
3288                 Cvar_RegisterVariable (&gl_fogblue);
3289                 Cvar_RegisterVariable (&gl_fogstart);
3290                 Cvar_RegisterVariable (&gl_fogend);
3291                 Cvar_RegisterVariable (&gl_skyclip);
3292         }
3293         Cvar_RegisterVariable(&r_motionblur);
3294         Cvar_RegisterVariable(&r_damageblur);
3295         Cvar_RegisterVariable(&r_motionblur_averaging);
3296         Cvar_RegisterVariable(&r_motionblur_randomize);
3297         Cvar_RegisterVariable(&r_motionblur_minblur);
3298         Cvar_RegisterVariable(&r_motionblur_maxblur);
3299         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3300         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3301         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3302         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3303         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3304         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3305         Cvar_RegisterVariable(&r_depthfirst);
3306         Cvar_RegisterVariable(&r_useinfinitefarclip);
3307         Cvar_RegisterVariable(&r_farclip_base);
3308         Cvar_RegisterVariable(&r_farclip_world);
3309         Cvar_RegisterVariable(&r_nearclip);
3310         Cvar_RegisterVariable(&r_deformvertexes);
3311         Cvar_RegisterVariable(&r_transparent);
3312         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3313         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3314         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3315         Cvar_RegisterVariable(&r_showoverdraw);
3316         Cvar_RegisterVariable(&r_showbboxes);
3317         Cvar_RegisterVariable(&r_showbboxes_client);
3318         Cvar_RegisterVariable(&r_showsurfaces);
3319         Cvar_RegisterVariable(&r_showtris);
3320         Cvar_RegisterVariable(&r_shownormals);
3321         Cvar_RegisterVariable(&r_showlighting);
3322         Cvar_RegisterVariable(&r_showcollisionbrushes);
3323         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3324         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3325         Cvar_RegisterVariable(&r_showdisabledepthtest);
3326         Cvar_RegisterVariable(&r_showspriteedges);
3327         Cvar_RegisterVariable(&r_showparticleedges);
3328         Cvar_RegisterVariable(&r_drawportals);
3329         Cvar_RegisterVariable(&r_drawentities);
3330         Cvar_RegisterVariable(&r_draw2d);
3331         Cvar_RegisterVariable(&r_drawworld);
3332         Cvar_RegisterVariable(&r_cullentities_trace);
3333         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3334         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3335         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3336         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3337         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3338         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3339         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3340         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3341         Cvar_RegisterVariable(&r_sortentities);
3342         Cvar_RegisterVariable(&r_drawviewmodel);
3343         Cvar_RegisterVariable(&r_drawexteriormodel);
3344         Cvar_RegisterVariable(&r_speeds);
3345         Cvar_RegisterVariable(&r_fullbrights);
3346         Cvar_RegisterVariable(&r_wateralpha);
3347         Cvar_RegisterVariable(&r_dynamic);
3348         Cvar_RegisterVariable(&r_fullbright_directed);
3349         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3350         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3351         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3352         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3353         Cvar_RegisterVariable(&r_fullbright);
3354         Cvar_RegisterVariable(&r_shadows);
3355         Cvar_RegisterVariable(&r_shadows_darken);
3356         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3357         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3358         Cvar_RegisterVariable(&r_shadows_throwdistance);
3359         Cvar_RegisterVariable(&r_shadows_throwdirection);
3360         Cvar_RegisterVariable(&r_shadows_focus);
3361         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3362         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3363         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3364         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3365         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3366         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3367         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3368         Cvar_RegisterVariable(&r_fog_exp2);
3369         Cvar_RegisterVariable(&r_fog_clear);
3370         Cvar_RegisterVariable(&r_drawfog);
3371         Cvar_RegisterVariable(&r_transparentdepthmasking);
3372         Cvar_RegisterVariable(&r_transparent_sortmindist);
3373         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3374         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3375         Cvar_RegisterVariable(&r_texture_dds_load);
3376         Cvar_RegisterVariable(&r_texture_dds_save);
3377         Cvar_RegisterVariable(&r_textureunits);
3378         Cvar_RegisterVariable(&gl_combine);
3379         Cvar_RegisterVariable(&r_usedepthtextures);
3380         Cvar_RegisterVariable(&r_viewfbo);
3381         Cvar_RegisterVariable(&r_rendertarget_debug);
3382         Cvar_RegisterVariable(&r_viewscale);
3383         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3384         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3385         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3386         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3387         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3388         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3389         Cvar_RegisterVariable(&r_glsl);
3390         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3391         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3392         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3393         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3394         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3395         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3396         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3397         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3398         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3399         Cvar_RegisterVariable(&r_glsl_postprocess);
3400         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3401         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3402         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3403         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3404         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3405         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3406         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3407         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3408         Cvar_RegisterVariable(&r_celshading);
3409         Cvar_RegisterVariable(&r_celoutlines);
3410
3411         Cvar_RegisterVariable(&r_water);
3412         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3413         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3414         Cvar_RegisterVariable(&r_water_clippingplanebias);
3415         Cvar_RegisterVariable(&r_water_refractdistort);
3416         Cvar_RegisterVariable(&r_water_reflectdistort);
3417         Cvar_RegisterVariable(&r_water_scissormode);
3418         Cvar_RegisterVariable(&r_water_lowquality);
3419         Cvar_RegisterVariable(&r_water_hideplayer);
3420
3421         Cvar_RegisterVariable(&r_lerpsprites);
3422         Cvar_RegisterVariable(&r_lerpmodels);
3423         Cvar_RegisterVariable(&r_lerplightstyles);
3424         Cvar_RegisterVariable(&r_waterscroll);
3425         Cvar_RegisterVariable(&r_bloom);
3426         Cvar_RegisterVariable(&r_colorfringe);
3427         Cvar_RegisterVariable(&r_bloom_colorscale);
3428         Cvar_RegisterVariable(&r_bloom_brighten);
3429         Cvar_RegisterVariable(&r_bloom_blur);
3430         Cvar_RegisterVariable(&r_bloom_resolution);
3431         Cvar_RegisterVariable(&r_bloom_colorexponent);
3432         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3433         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3434         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3435         Cvar_RegisterVariable(&r_hdr_glowintensity);
3436         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3437         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3438         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3439         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3440         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3441         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3442         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3443         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3444         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3445         Cvar_RegisterVariable(&developer_texturelogging);
3446         Cvar_RegisterVariable(&gl_lightmaps);
3447         Cvar_RegisterVariable(&r_test);
3448         Cvar_RegisterVariable(&r_batch_multidraw);
3449         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3450         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3451         Cvar_RegisterVariable(&r_glsl_skeletal);
3452         Cvar_RegisterVariable(&r_glsl_saturation);
3453         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3454         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3455         Cvar_RegisterVariable(&r_framedatasize);
3456         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3457                 Cvar_RegisterVariable(&r_buffermegs[i]);
3458         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3459         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3460                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3461 #ifdef DP_MOBILETOUCH
3462         // GLES devices have terrible depth precision in general, so...
3463         Cvar_SetValueQuick(&r_nearclip, 4);
3464         Cvar_SetValueQuick(&r_farclip_base, 4096);
3465         Cvar_SetValueQuick(&r_farclip_world, 0);
3466         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3467 #endif
3468         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3469 }
3470
3471 void Render_Init(void)
3472 {
3473         gl_backend_init();
3474         R_Textures_Init();
3475         GL_Main_Init();
3476         Font_Init();
3477         GL_Draw_Init();
3478         R_Shadow_Init();
3479         R_Sky_Init();
3480         GL_Surf_Init();
3481         Sbar_Init();
3482         R_Particles_Init();
3483         R_Explosion_Init();
3484         R_LightningBeams_Init();
3485         Mod_RenderInit();
3486 }
3487
3488 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3489 {
3490         int i;
3491         mplane_t *p;
3492         if (r_trippy.integer)
3493                 return false;
3494         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3495         {
3496                 p = r_refdef.view.frustum + i;
3497                 switch(p->signbits)
3498                 {
3499                 default:
3500                 case 0:
3501                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3502                                 return true;
3503                         break;
3504                 case 1:
3505                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3506                                 return true;
3507                         break;
3508                 case 2:
3509                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3510                                 return true;
3511                         break;
3512                 case 3:
3513                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3514                                 return true;
3515                         break;
3516                 case 4:
3517                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3518                                 return true;
3519                         break;
3520                 case 5:
3521                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3522                                 return true;
3523                         break;
3524                 case 6:
3525                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3526                                 return true;
3527                         break;
3528                 case 7:
3529                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3530                                 return true;
3531                         break;
3532                 }
3533         }
3534         return false;
3535 }
3536
3537 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3538 {
3539         int i;
3540         const mplane_t *p;
3541         if (r_trippy.integer)
3542                 return false;
3543         for (i = 0;i < numplanes;i++)
3544         {
3545                 p = planes + i;
3546                 switch(p->signbits)
3547                 {
3548                 default:
3549                 case 0:
3550                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3551                                 return true;
3552                         break;
3553                 case 1:
3554                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3555                                 return true;
3556                         break;
3557                 case 2:
3558                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3559                                 return true;
3560                         break;
3561                 case 3:
3562                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3563                                 return true;
3564                         break;
3565                 case 4:
3566                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3567                                 return true;
3568                         break;
3569                 case 5:
3570                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3571                                 return true;
3572                         break;
3573                 case 6:
3574                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3575                                 return true;
3576                         break;
3577                 case 7:
3578                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3579                                 return true;
3580                         break;
3581                 }
3582         }
3583         return false;
3584 }
3585
3586 //==================================================================================
3587
3588 // LadyHavoc: this stores temporary data used within the same frame
3589
3590 typedef struct r_framedata_mem_s
3591 {
3592         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3593         size_t size; // how much usable space
3594         size_t current; // how much space in use
3595         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3596         size_t wantedsize; // how much space was allocated
3597         unsigned char *data; // start of real data (16byte aligned)
3598 }
3599 r_framedata_mem_t;
3600
3601 static r_framedata_mem_t *r_framedata_mem;
3602
3603 void R_FrameData_Reset(void)
3604 {
3605         while (r_framedata_mem)
3606         {
3607                 r_framedata_mem_t *next = r_framedata_mem->purge;
3608                 Mem_Free(r_framedata_mem);
3609                 r_framedata_mem = next;
3610         }
3611 }
3612
3613 static void R_FrameData_Resize(qboolean mustgrow)
3614 {
3615         size_t wantedsize;
3616         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3617         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3618         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3619         {
3620                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3621                 newmem->wantedsize = wantedsize;
3622                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3623                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3624                 newmem->current = 0;
3625                 newmem->mark = 0;
3626                 newmem->purge = r_framedata_mem;
3627                 r_framedata_mem = newmem;
3628         }
3629 }
3630
3631 void R_FrameData_NewFrame(void)
3632 {
3633         R_FrameData_Resize(false);
3634         if (!r_framedata_mem)
3635                 return;
3636         // if we ran out of space on the last frame, free the old memory now
3637         while (r_framedata_mem->purge)
3638         {
3639                 // repeatedly remove the second item in the list, leaving only head
3640                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3641                 Mem_Free(r_framedata_mem->purge);
3642                 r_framedata_mem->purge = next;
3643         }
3644         // reset the current mem pointer
3645         r_framedata_mem->current = 0;
3646         r_framedata_mem->mark = 0;
3647 }
3648
3649 void *R_FrameData_Alloc(size_t size)
3650 {
3651         void *data;
3652         float newvalue;
3653
3654         // align to 16 byte boundary - the data pointer is already aligned, so we
3655         // only need to ensure the size of every allocation is also aligned
3656         size = (size + 15) & ~15;
3657
3658         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3659         {
3660                 // emergency - we ran out of space, allocate more memory
3661                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3662                 newvalue = r_framedatasize.value * 2.0f;
3663                 // 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
3664                 if (sizeof(size_t) >= 8)
3665                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3666                 else
3667                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3668                 // this might not be a growing it, but we'll allocate another buffer every time
3669                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3670                 R_FrameData_Resize(true);
3671         }
3672
3673         data = r_framedata_mem->data + r_framedata_mem->current;
3674         r_framedata_mem->current += size;
3675
3676         // count the usage for stats
3677         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3678         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3679
3680         return (void *)data;
3681 }
3682
3683 void *R_FrameData_Store(size_t size, void *data)
3684 {
3685         void *d = R_FrameData_Alloc(size);
3686         if (d && data)
3687                 memcpy(d, data, size);
3688         return d;
3689 }
3690
3691 void R_FrameData_SetMark(void)
3692 {
3693         if (!r_framedata_mem)
3694                 return;
3695         r_framedata_mem->mark = r_framedata_mem->current;
3696 }
3697
3698 void R_FrameData_ReturnToMark(void)
3699 {
3700         if (!r_framedata_mem)
3701                 return;
3702         r_framedata_mem->current = r_framedata_mem->mark;
3703 }
3704
3705 //==================================================================================
3706
3707 // avoid reusing the same buffer objects on consecutive frames
3708 #define R_BUFFERDATA_CYCLE 3
3709
3710 typedef struct r_bufferdata_buffer_s
3711 {
3712         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3713         size_t size; // how much usable space
3714         size_t current; // how much space in use
3715         r_meshbuffer_t *buffer; // the buffer itself
3716 }
3717 r_bufferdata_buffer_t;
3718
3719 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3720 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3721
3722 /// frees all dynamic buffers
3723 void R_BufferData_Reset(void)
3724 {
3725         int cycle, type;
3726         r_bufferdata_buffer_t **p, *mem;
3727         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3728         {
3729                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3730                 {
3731                         // free all buffers
3732                         p = &r_bufferdata_buffer[cycle][type];
3733                         while (*p)
3734                         {
3735                                 mem = *p;
3736                                 *p = (*p)->purge;
3737                                 if (mem->buffer)
3738                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3739                                 Mem_Free(mem);
3740                         }
3741                 }
3742         }
3743 }
3744
3745 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3746 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3747 {
3748         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3749         size_t size;
3750         float newvalue = r_buffermegs[type].value;
3751
3752         // increase the cvar if we have to (but only if we already have a mem)
3753         if (mustgrow && mem)
3754                 newvalue *= 2.0f;
3755         newvalue = bound(0.25f, newvalue, 256.0f);
3756         while (newvalue * 1024*1024 < minsize)
3757                 newvalue *= 2.0f;
3758
3759         // clamp the cvar to valid range
3760         newvalue = bound(0.25f, newvalue, 256.0f);
3761         if (r_buffermegs[type].value != newvalue)
3762                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3763
3764         // calculate size in bytes
3765         size = (size_t)(newvalue * 1024*1024);
3766         size = bound(131072, size, 256*1024*1024);
3767
3768         // allocate a new buffer if the size is different (purge old one later)
3769         // or if we were told we must grow the buffer
3770         if (!mem || mem->size != size || mustgrow)
3771         {
3772                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3773                 mem->size = size;
3774                 mem->current = 0;
3775                 if (type == R_BUFFERDATA_VERTEX)
3776                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3777                 else if (type == R_BUFFERDATA_INDEX16)
3778                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3779                 else if (type == R_BUFFERDATA_INDEX32)
3780                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3781                 else if (type == R_BUFFERDATA_UNIFORM)
3782                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3783                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3784                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3785         }
3786 }
3787
3788 void R_BufferData_NewFrame(void)
3789 {
3790         int type;
3791         r_bufferdata_buffer_t **p, *mem;
3792         // cycle to the next frame's buffers
3793         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3794         // if we ran out of space on the last time we used these buffers, free the old memory now
3795         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3796         {
3797                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3798                 {
3799                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3800                         // free all but the head buffer, this is how we recycle obsolete
3801                         // buffers after they are no longer in use
3802                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3803                         while (*p)
3804                         {
3805                                 mem = *p;
3806                                 *p = (*p)->purge;
3807                                 if (mem->buffer)
3808                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3809                                 Mem_Free(mem);
3810                         }
3811                         // reset the current offset
3812                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3813                 }
3814         }
3815 }
3816
3817 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3818 {
3819         r_bufferdata_buffer_t *mem;
3820         int offset = 0;
3821         int padsize;
3822
3823         *returnbufferoffset = 0;
3824
3825         // align size to a byte boundary appropriate for the buffer type, this
3826         // makes all allocations have aligned start offsets
3827         if (type == R_BUFFERDATA_UNIFORM)
3828                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3829         else
3830                 padsize = (datasize + 15) & ~15;
3831
3832         // if we ran out of space in this buffer we must allocate a new one
3833         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)
3834                 R_BufferData_Resize(type, true, padsize);
3835
3836         // if the resize did not give us enough memory, fail
3837         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)
3838                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3839
3840         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3841         offset = (int)mem->current;
3842         mem->current += padsize;
3843
3844         // upload the data to the buffer at the chosen offset
3845         if (offset == 0)
3846                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3847         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3848
3849         // count the usage for stats
3850         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3851         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3852
3853         // return the buffer offset
3854         *returnbufferoffset = offset;
3855
3856         return mem->buffer;
3857 }
3858
3859 //==================================================================================
3860
3861 // LadyHavoc: animcache originally written by Echon, rewritten since then
3862
3863 /**
3864  * Animation cache prevents re-generating mesh data for an animated model
3865  * multiple times in one frame for lighting, shadowing, reflections, etc.
3866  */
3867
3868 void R_AnimCache_Free(void)
3869 {
3870 }
3871
3872 void R_AnimCache_ClearCache(void)
3873 {
3874         int i;
3875         entity_render_t *ent;
3876
3877         for (i = 0;i < r_refdef.scene.numentities;i++)
3878         {
3879                 ent = r_refdef.scene.entities[i];
3880                 ent->animcache_vertex3f = NULL;
3881                 ent->animcache_vertex3f_vertexbuffer = NULL;
3882                 ent->animcache_vertex3f_bufferoffset = 0;
3883                 ent->animcache_normal3f = NULL;
3884                 ent->animcache_normal3f_vertexbuffer = NULL;
3885                 ent->animcache_normal3f_bufferoffset = 0;
3886                 ent->animcache_svector3f = NULL;
3887                 ent->animcache_svector3f_vertexbuffer = NULL;
3888                 ent->animcache_svector3f_bufferoffset = 0;
3889                 ent->animcache_tvector3f = NULL;
3890                 ent->animcache_tvector3f_vertexbuffer = NULL;
3891                 ent->animcache_tvector3f_bufferoffset = 0;
3892                 ent->animcache_skeletaltransform3x4 = NULL;
3893                 ent->animcache_skeletaltransform3x4buffer = NULL;
3894                 ent->animcache_skeletaltransform3x4offset = 0;
3895                 ent->animcache_skeletaltransform3x4size = 0;
3896         }
3897 }
3898
3899 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3900 {
3901         dp_model_t *model = ent->model;
3902         int numvertices;
3903
3904         // see if this ent is worth caching
3905         if (!model || !model->Draw || !model->AnimateVertices)
3906                 return false;
3907         // nothing to cache if it contains no animations and has no skeleton
3908         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3909                 return false;
3910         // see if it is already cached for gpuskeletal
3911         if (ent->animcache_skeletaltransform3x4)
3912                 return false;
3913         // see if it is already cached as a mesh
3914         if (ent->animcache_vertex3f)
3915         {
3916                 // check if we need to add normals or tangents
3917                 if (ent->animcache_normal3f)
3918                         wantnormals = false;
3919                 if (ent->animcache_svector3f)
3920                         wanttangents = false;
3921                 if (!wantnormals && !wanttangents)
3922                         return false;
3923         }
3924
3925         // check which kind of cache we need to generate
3926         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3927         {
3928                 // cache the skeleton so the vertex shader can use it
3929                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3930                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3931                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3932                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3933                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3934                 // note: this can fail if the buffer is at the grow limit
3935                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3936                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3937         }
3938         else if (ent->animcache_vertex3f)
3939         {
3940                 // mesh was already cached but we may need to add normals/tangents
3941                 // (this only happens with multiple views, reflections, cameras, etc)
3942                 if (wantnormals || wanttangents)
3943                 {
3944                         numvertices = model->surfmesh.num_vertices;
3945                         if (wantnormals)
3946                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3947                         if (wanttangents)
3948                         {
3949                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3950                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3951                         }
3952                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3953                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3954                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3955                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3956                 }
3957         }
3958         else
3959         {
3960                 // generate mesh cache
3961                 numvertices = model->surfmesh.num_vertices;
3962                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3963                 if (wantnormals)
3964                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3965                 if (wanttangents)
3966                 {
3967                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3968                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3969                 }
3970                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3971                 if (wantnormals || wanttangents)
3972                 {
3973                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3974                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3975                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3976                 }
3977                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3978                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3979                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3980         }
3981         return true;
3982 }
3983
3984 void R_AnimCache_CacheVisibleEntities(void)
3985 {
3986         int i;
3987
3988         // TODO: thread this
3989         // NOTE: R_PrepareRTLights() also caches entities
3990
3991         for (i = 0;i < r_refdef.scene.numentities;i++)
3992                 if (r_refdef.viewcache.entityvisible[i])
3993                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3994 }
3995
3996 //==================================================================================
3997
3998 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
3999 {
4000         long unsigned int i;
4001         int j;
4002         vec3_t eyemins, eyemaxs;
4003         vec3_t boxmins, boxmaxs;
4004         vec3_t padmins, padmaxs;
4005         vec3_t start;
4006         vec3_t end;
4007         dp_model_t *model = r_refdef.scene.worldmodel;
4008         static vec3_t positions[] = {
4009                 { 0.5f, 0.5f, 0.5f },
4010                 { 0.0f, 0.0f, 0.0f },
4011                 { 0.0f, 0.0f, 1.0f },
4012                 { 0.0f, 1.0f, 0.0f },
4013                 { 0.0f, 1.0f, 1.0f },
4014                 { 1.0f, 0.0f, 0.0f },
4015                 { 1.0f, 0.0f, 1.0f },
4016                 { 1.0f, 1.0f, 0.0f },
4017                 { 1.0f, 1.0f, 1.0f },
4018         };
4019
4020         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4021         if (numsamples < 0)
4022                 return true;
4023
4024         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4025         if (!r_refdef.view.usevieworiginculling)
4026                 return true;
4027
4028         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4029                 return true;
4030
4031         // expand the eye box a little
4032         eyemins[0] = eye[0] - eyejitter;
4033         eyemaxs[0] = eye[0] + eyejitter;
4034         eyemins[1] = eye[1] - eyejitter;
4035         eyemaxs[1] = eye[1] + eyejitter;
4036         eyemins[2] = eye[2] - eyejitter;
4037         eyemaxs[2] = eye[2] + eyejitter;
4038         // expand the box a little
4039         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4040         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4041         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4042         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4043         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4044         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4045         // make an even larger box for the acceptable area
4046         padmins[0] = boxmins[0] - pad;
4047         padmaxs[0] = boxmaxs[0] + pad;
4048         padmins[1] = boxmins[1] - pad;
4049         padmaxs[1] = boxmaxs[1] + pad;
4050         padmins[2] = boxmins[2] - pad;
4051         padmaxs[2] = boxmaxs[2] + pad;
4052
4053         // return true if eye overlaps enlarged box
4054         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4055                 return true;
4056
4057         // try specific positions in the box first - note that these can be cached
4058         if (r_cullentities_trace_entityocclusion.integer)
4059         {
4060                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4061                 {
4062                         trace_t trace;
4063                         VectorCopy(eye, start);
4064                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4065                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4066                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4067                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4068                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4069                         // not picky - if the trace ended anywhere in the box we're good
4070                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4071                                 return true;
4072                 }
4073         }
4074         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4075                 return true;
4076
4077         // try various random positions
4078         for (j = 0; j < numsamples; j++)
4079         {
4080                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4081                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4082                 if (r_cullentities_trace_entityocclusion.integer)
4083                 {
4084                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4085                         // not picky - if the trace ended anywhere in the box we're good
4086                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4087                                 return true;
4088                 }
4089                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4090                         return true;
4091         }
4092
4093         return false;
4094 }
4095
4096
4097 static void R_View_UpdateEntityVisible (void)
4098 {
4099         int i;
4100         int renderimask;
4101         int samples;
4102         entity_render_t *ent;
4103
4104         if (r_refdef.envmap || r_fb.water.hideplayer)
4105                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4106         else if (chase_active.integer || r_fb.water.renderingscene)
4107                 renderimask = RENDER_VIEWMODEL;
4108         else
4109                 renderimask = RENDER_EXTERIORMODEL;
4110         if (!r_drawviewmodel.integer)
4111                 renderimask |= RENDER_VIEWMODEL;
4112         if (!r_drawexteriormodel.integer)
4113                 renderimask |= RENDER_EXTERIORMODEL;
4114         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4115         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4116         {
4117                 // worldmodel can check visibility
4118                 for (i = 0;i < r_refdef.scene.numentities;i++)
4119                 {
4120                         ent = r_refdef.scene.entities[i];
4121                         if (!(ent->flags & renderimask))
4122                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4123                         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))
4124                                 r_refdef.viewcache.entityvisible[i] = true;
4125                 }
4126         }
4127         else
4128         {
4129                 // no worldmodel or it can't check visibility
4130                 for (i = 0;i < r_refdef.scene.numentities;i++)
4131                 {
4132                         ent = r_refdef.scene.entities[i];
4133                         if (!(ent->flags & renderimask))
4134                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4135                                 r_refdef.viewcache.entityvisible[i] = true;
4136                 }
4137         }
4138         if (r_cullentities_trace.integer)
4139         {
4140                 for (i = 0;i < r_refdef.scene.numentities;i++)
4141                 {
4142                         if (!r_refdef.viewcache.entityvisible[i])
4143                                 continue;
4144                         ent = r_refdef.scene.entities[i];
4145                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4146                         {
4147                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4148                                 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))
4149                                         ent->last_trace_visibility = host.realtime;
4150                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4151                                         r_refdef.viewcache.entityvisible[i] = 0;
4152                         }
4153                 }
4154         }
4155 }
4156
4157 /// only used if skyrendermasked, and normally returns false
4158 static int R_DrawBrushModelsSky (void)
4159 {
4160         int i, sky;
4161         entity_render_t *ent;
4162
4163         sky = false;
4164         for (i = 0;i < r_refdef.scene.numentities;i++)
4165         {
4166                 if (!r_refdef.viewcache.entityvisible[i])
4167                         continue;
4168                 ent = r_refdef.scene.entities[i];
4169                 if (!ent->model || !ent->model->DrawSky)
4170                         continue;
4171                 ent->model->DrawSky(ent);
4172                 sky = true;
4173         }
4174         return sky;
4175 }
4176
4177 static void R_DrawNoModel(entity_render_t *ent);
4178 static void R_DrawModels(void)
4179 {
4180         int i;
4181         entity_render_t *ent;
4182
4183         for (i = 0;i < r_refdef.scene.numentities;i++)
4184         {
4185                 if (!r_refdef.viewcache.entityvisible[i])
4186                         continue;
4187                 ent = r_refdef.scene.entities[i];
4188                 r_refdef.stats[r_stat_entities]++;
4189                 /*
4190                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4191                 {
4192                         vec3_t f, l, u, o;
4193                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4194                         Con_Printf("R_DrawModels\n");
4195                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4196                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4197                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4198                 }
4199                 */
4200                 if (ent->model && ent->model->Draw != NULL)
4201                         ent->model->Draw(ent);
4202                 else
4203                         R_DrawNoModel(ent);
4204         }
4205 }
4206
4207 static void R_DrawModelsDepth(void)
4208 {
4209         int i;
4210         entity_render_t *ent;
4211
4212         for (i = 0;i < r_refdef.scene.numentities;i++)
4213         {
4214                 if (!r_refdef.viewcache.entityvisible[i])
4215                         continue;
4216                 ent = r_refdef.scene.entities[i];
4217                 if (ent->model && ent->model->DrawDepth != NULL)
4218                         ent->model->DrawDepth(ent);
4219         }
4220 }
4221
4222 static void R_DrawModelsDebug(void)
4223 {
4224         int i;
4225         entity_render_t *ent;
4226
4227         for (i = 0;i < r_refdef.scene.numentities;i++)
4228         {
4229                 if (!r_refdef.viewcache.entityvisible[i])
4230                         continue;
4231                 ent = r_refdef.scene.entities[i];
4232                 if (ent->model && ent->model->DrawDebug != NULL)
4233                         ent->model->DrawDebug(ent);
4234         }
4235 }
4236
4237 static void R_DrawModelsAddWaterPlanes(void)
4238 {
4239         int i;
4240         entity_render_t *ent;
4241
4242         for (i = 0;i < r_refdef.scene.numentities;i++)
4243         {
4244                 if (!r_refdef.viewcache.entityvisible[i])
4245                         continue;
4246                 ent = r_refdef.scene.entities[i];
4247                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4248                         ent->model->DrawAddWaterPlanes(ent);
4249         }
4250 }
4251
4252 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}};
4253
4254 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4255 {
4256         if (r_hdr_irisadaptation.integer)
4257         {
4258                 vec3_t p;
4259                 vec3_t ambient;
4260                 vec3_t diffuse;
4261                 vec3_t diffusenormal;
4262                 vec3_t forward;
4263                 vec_t brightness = 0.0f;
4264                 vec_t goal;
4265                 vec_t current;
4266                 vec_t d;
4267                 int c;
4268                 VectorCopy(r_refdef.view.forward, forward);
4269                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4270                 {
4271                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4272                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4273                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4274                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4275                         d = DotProduct(forward, diffusenormal);
4276                         brightness += VectorLength(ambient);
4277                         if (d > 0)
4278                                 brightness += d * VectorLength(diffuse);
4279                 }
4280                 brightness *= 1.0f / c;
4281                 brightness += 0.00001f; // make sure it's never zero
4282                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4283                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4284                 current = r_hdr_irisadaptation_value.value;
4285                 if (current < goal)
4286                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4287                 else if (current > goal)
4288                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4289                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4290                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4291         }
4292         else if (r_hdr_irisadaptation_value.value != 1.0f)
4293                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4294 }
4295
4296 static void R_View_SetFrustum(const int *scissor)
4297 {
4298         int i;
4299         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4300         vec3_t forward, left, up, origin, v;
4301
4302         if(scissor)
4303         {
4304                 // flipped x coordinates (because x points left here)
4305                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4306                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4307                 // non-flipped y coordinates
4308                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4309                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4310         }
4311
4312         // we can't trust r_refdef.view.forward and friends in reflected scenes
4313         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4314
4315 #if 0
4316         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4317         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4318         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4319         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4320         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4321         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4322         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4323         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4324         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4325         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4326         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4327         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4328 #endif
4329
4330 #if 0
4331         zNear = r_refdef.nearclip;
4332         nudge = 1.0 - 1.0 / (1<<23);
4333         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4334         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4335         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4336         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4337         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4338         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4339         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4340         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4341 #endif
4342
4343
4344
4345 #if 0
4346         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4347         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4348         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4349         r_refdef.view.frustum[0].dist = m[15] - m[12];
4350
4351         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4352         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4353         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4354         r_refdef.view.frustum[1].dist = m[15] + m[12];
4355
4356         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4357         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4358         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4359         r_refdef.view.frustum[2].dist = m[15] - m[13];
4360
4361         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4362         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4363         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4364         r_refdef.view.frustum[3].dist = m[15] + m[13];
4365
4366         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4367         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4368         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4369         r_refdef.view.frustum[4].dist = m[15] - m[14];
4370
4371         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4372         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4373         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4374         r_refdef.view.frustum[5].dist = m[15] + m[14];
4375 #endif
4376
4377         if (r_refdef.view.useperspective)
4378         {
4379                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4380                 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]);
4381                 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]);
4382                 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]);
4383                 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]);
4384
4385                 // then the normals from the corners relative to origin
4386                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4387                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4388                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4389                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4390
4391                 // in a NORMAL view, forward cross left == up
4392                 // in a REFLECTED view, forward cross left == down
4393                 // so our cross products above need to be adjusted for a left handed coordinate system
4394                 CrossProduct(forward, left, v);
4395                 if(DotProduct(v, up) < 0)
4396                 {
4397                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4398                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4399                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4400                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4401                 }
4402
4403                 // Leaving those out was a mistake, those were in the old code, and they
4404                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4405                 // I couldn't reproduce it after adding those normalizations. --blub
4406                 VectorNormalize(r_refdef.view.frustum[0].normal);
4407                 VectorNormalize(r_refdef.view.frustum[1].normal);
4408                 VectorNormalize(r_refdef.view.frustum[2].normal);
4409                 VectorNormalize(r_refdef.view.frustum[3].normal);
4410
4411                 // make the corners absolute
4412                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4413                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4414                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4415                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4416
4417                 // one more normal
4418                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4419
4420                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4421                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4422                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4423                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4424                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4425         }
4426         else
4427         {
4428                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4429                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4430                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4431                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4432                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4433                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4434                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4435                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4436                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4437                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4438         }
4439         r_refdef.view.numfrustumplanes = 5;
4440
4441         if (r_refdef.view.useclipplane)
4442         {
4443                 r_refdef.view.numfrustumplanes = 6;
4444                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4445         }
4446
4447         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4448                 PlaneClassify(r_refdef.view.frustum + i);
4449
4450         // LadyHavoc: note to all quake engine coders, Quake had a special case
4451         // for 90 degrees which assumed a square view (wrong), so I removed it,
4452         // Quake2 has it disabled as well.
4453
4454         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4455         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4456         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4457         //PlaneClassify(&frustum[0]);
4458
4459         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4460         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4461         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4462         //PlaneClassify(&frustum[1]);
4463
4464         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4465         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4466         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4467         //PlaneClassify(&frustum[2]);
4468
4469         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4470         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4471         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4472         //PlaneClassify(&frustum[3]);
4473
4474         // nearclip plane
4475         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4476         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4477         //PlaneClassify(&frustum[4]);
4478 }
4479
4480 static void R_View_UpdateWithScissor(const int *myscissor)
4481 {
4482         R_Main_ResizeViewCache();
4483         R_View_SetFrustum(myscissor);
4484         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4485         R_View_UpdateEntityVisible();
4486 }
4487
4488 static void R_View_Update(void)
4489 {
4490         R_Main_ResizeViewCache();
4491         R_View_SetFrustum(NULL);
4492         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4493         R_View_UpdateEntityVisible();
4494 }
4495
4496 float viewscalefpsadjusted = 1.0f;
4497
4498 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4499 {
4500         const float *customclipplane = NULL;
4501         float plane[4];
4502         int /*rtwidth,*/ rtheight;
4503         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4504         {
4505                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4506                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4507                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4508                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4509                         dist = r_refdef.view.clipplane.dist;
4510                 plane[0] = r_refdef.view.clipplane.normal[0];
4511                 plane[1] = r_refdef.view.clipplane.normal[1];
4512                 plane[2] = r_refdef.view.clipplane.normal[2];
4513                 plane[3] = -dist;
4514                 customclipplane = plane;
4515         }
4516
4517         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4518         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4519
4520         if (!r_refdef.view.useperspective)
4521                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4522         else if (vid.stencil && r_useinfinitefarclip.integer)
4523                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4524         else
4525                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4526         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4527         R_SetViewport(&r_refdef.view.viewport);
4528 }
4529
4530 void R_EntityMatrix(const matrix4x4_t *matrix)
4531 {
4532         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4533         {
4534                 gl_modelmatrixchanged = false;
4535                 gl_modelmatrix = *matrix;
4536                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4537                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4538                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4539                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4540                 CHECKGLERROR
4541                 switch(vid.renderpath)
4542                 {
4543                 case RENDERPATH_GL32:
4544                 case RENDERPATH_GLES2:
4545                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4546                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4547                         break;
4548                 }
4549         }
4550 }
4551
4552 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4553 {
4554         r_viewport_t viewport;
4555
4556         CHECKGLERROR
4557
4558         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4559         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4560         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4561         R_SetViewport(&viewport);
4562         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4563         GL_Color(1, 1, 1, 1);
4564         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4565         GL_BlendFunc(GL_ONE, GL_ZERO);
4566         GL_ScissorTest(false);
4567         GL_DepthMask(false);
4568         GL_DepthRange(0, 1);
4569         GL_DepthTest(false);
4570         GL_DepthFunc(GL_LEQUAL);
4571         R_EntityMatrix(&identitymatrix);
4572         R_Mesh_ResetTextureState();
4573         GL_PolygonOffset(0, 0);
4574         switch(vid.renderpath)
4575         {
4576         case RENDERPATH_GL32:
4577         case RENDERPATH_GLES2:
4578                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4579                 break;
4580         }
4581         GL_CullFace(GL_NONE);
4582
4583         CHECKGLERROR
4584 }
4585
4586 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4587 {
4588         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4589 }
4590
4591 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4592 {
4593         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4594         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4595         GL_Color(1, 1, 1, 1);
4596         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4597         GL_BlendFunc(GL_ONE, GL_ZERO);
4598         GL_ScissorTest(true);
4599         GL_DepthMask(true);
4600         GL_DepthRange(0, 1);
4601         GL_DepthTest(true);
4602         GL_DepthFunc(GL_LEQUAL);
4603         R_EntityMatrix(&identitymatrix);
4604         R_Mesh_ResetTextureState();
4605         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4606         switch(vid.renderpath)
4607         {
4608         case RENDERPATH_GL32:
4609         case RENDERPATH_GLES2:
4610                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4611                 break;
4612         }
4613         GL_CullFace(r_refdef.view.cullface_back);
4614 }
4615
4616 /*
4617 ================
4618 R_RenderView_UpdateViewVectors
4619 ================
4620 */
4621 void R_RenderView_UpdateViewVectors(void)
4622 {
4623         // break apart the view matrix into vectors for various purposes
4624         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4625         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4626         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4627         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4628         // make an inverted copy of the view matrix for tracking sprites
4629         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4630 }
4631
4632 void R_RenderTarget_FreeUnused(qboolean force)
4633 {
4634         unsigned int i, j, end;
4635         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4636         for (i = 0; i < end; i++)
4637         {
4638                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4639                 // free resources for rendertargets that have not been used for a while
4640                 // (note: this check is run after the frame render, so any targets used
4641                 // this frame will not be affected even at low framerates)
4642                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4643                 {
4644                         if (r->fbo)
4645                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4646                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4647                                 if (r->colortexture[j])
4648                                         R_FreeTexture(r->colortexture[j]);
4649                         if (r->depthtexture)
4650                                 R_FreeTexture(r->depthtexture);
4651                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4652                 }
4653         }
4654 }
4655
4656 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4657 {
4658         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4659         x1 = x * iw;
4660         x2 = (x + w) * iw;
4661         y1 = (th - y) * ih;
4662         y2 = (th - y - h) * ih;
4663         texcoord2f[0] = x1;
4664         texcoord2f[2] = x2;
4665         texcoord2f[4] = x2;
4666         texcoord2f[6] = x1;
4667         texcoord2f[1] = y1;
4668         texcoord2f[3] = y1;
4669         texcoord2f[5] = y2;
4670         texcoord2f[7] = y2;
4671 }
4672
4673 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4674 {
4675         unsigned int i, j, end;
4676         r_rendertarget_t *r = NULL;
4677         char vabuf[256];
4678         // first try to reuse an existing slot if possible
4679         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4680         for (i = 0; i < end; i++)
4681         {
4682                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4683                 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)
4684                         break;
4685         }
4686         if (i == end)
4687         {
4688                 // no unused exact match found, so we have to make one in the first unused slot
4689                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4690                 r->texturewidth = texturewidth;
4691                 r->textureheight = textureheight;
4692                 r->colortextype[0] = colortextype0;
4693                 r->colortextype[1] = colortextype1;
4694                 r->colortextype[2] = colortextype2;
4695                 r->colortextype[3] = colortextype3;
4696                 r->depthtextype = depthtextype;
4697                 r->depthisrenderbuffer = depthisrenderbuffer;
4698                 for (j = 0; j < 4; j++)
4699                         if (r->colortextype[j])
4700                                 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);
4701                 if (r->depthtextype)
4702                 {
4703                         if (r->depthisrenderbuffer)
4704                                 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);
4705                         else
4706                                 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);
4707                 }
4708                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4709         }
4710         r_refdef.stats[r_stat_rendertargets_used]++;
4711         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4712         r->lastusetime = host.realtime;
4713         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4714         return r;
4715 }
4716
4717 static void R_Water_StartFrame(int viewwidth, int viewheight)
4718 {
4719         int waterwidth, waterheight;
4720
4721         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4722                 return;
4723
4724         // set waterwidth and waterheight to the water resolution that will be
4725         // used (often less than the screen resolution for faster rendering)
4726         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4727         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4728
4729         if (!r_water.integer || r_showsurfaces.integer)
4730                 waterwidth = waterheight = 0;
4731
4732         // set up variables that will be used in shader setup
4733         r_fb.water.waterwidth = waterwidth;
4734         r_fb.water.waterheight = waterheight;
4735         r_fb.water.texturewidth = waterwidth;
4736         r_fb.water.textureheight = waterheight;
4737         r_fb.water.camerawidth = waterwidth;
4738         r_fb.water.cameraheight = waterheight;
4739         r_fb.water.screenscale[0] = 0.5f;
4740         r_fb.water.screenscale[1] = 0.5f;
4741         r_fb.water.screencenter[0] = 0.5f;
4742         r_fb.water.screencenter[1] = 0.5f;
4743         r_fb.water.enabled = waterwidth != 0;
4744
4745         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4746         r_fb.water.numwaterplanes = 0;
4747 }
4748
4749 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4750 {
4751         int planeindex, bestplaneindex, vertexindex;
4752         vec3_t mins, maxs, normal, center, v, n;
4753         vec_t planescore, bestplanescore;
4754         mplane_t plane;
4755         r_waterstate_waterplane_t *p;
4756         texture_t *t = R_GetCurrentTexture(surface->texture);
4757
4758         rsurface.texture = t;
4759         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4760         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4761         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4762                 return;
4763         // average the vertex normals, find the surface bounds (after deformvertexes)
4764         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4765         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4766         VectorCopy(n, normal);
4767         VectorCopy(v, mins);
4768         VectorCopy(v, maxs);
4769         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4770         {
4771                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4772                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4773                 VectorAdd(normal, n, normal);
4774                 mins[0] = min(mins[0], v[0]);
4775                 mins[1] = min(mins[1], v[1]);
4776                 mins[2] = min(mins[2], v[2]);
4777                 maxs[0] = max(maxs[0], v[0]);
4778                 maxs[1] = max(maxs[1], v[1]);
4779                 maxs[2] = max(maxs[2], v[2]);
4780         }
4781         VectorNormalize(normal);
4782         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4783
4784         VectorCopy(normal, plane.normal);
4785         VectorNormalize(plane.normal);
4786         plane.dist = DotProduct(center, plane.normal);
4787         PlaneClassify(&plane);
4788         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4789         {
4790                 // skip backfaces (except if nocullface is set)
4791 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4792 //                      return;
4793                 VectorNegate(plane.normal, plane.normal);
4794                 plane.dist *= -1;
4795                 PlaneClassify(&plane);
4796         }
4797
4798
4799         // find a matching plane if there is one
4800         bestplaneindex = -1;
4801         bestplanescore = 1048576.0f;
4802         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4803         {
4804                 if(p->camera_entity == t->camera_entity)
4805                 {
4806                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4807                         if (bestplaneindex < 0 || bestplanescore > planescore)
4808                         {
4809                                 bestplaneindex = planeindex;
4810                                 bestplanescore = planescore;
4811                         }
4812                 }
4813         }
4814         planeindex = bestplaneindex;
4815
4816         // if this surface does not fit any known plane rendered this frame, add one
4817         if (planeindex < 0 || bestplanescore > 0.001f)
4818         {
4819                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4820                 {
4821                         // store the new plane
4822                         planeindex = r_fb.water.numwaterplanes++;
4823                         p = r_fb.water.waterplanes + planeindex;
4824                         p->plane = plane;
4825                         // clear materialflags and pvs
4826                         p->materialflags = 0;
4827                         p->pvsvalid = false;
4828                         p->camera_entity = t->camera_entity;
4829                         VectorCopy(mins, p->mins);
4830                         VectorCopy(maxs, p->maxs);
4831                 }
4832                 else
4833                 {
4834                         // We're totally screwed.
4835                         return;
4836                 }
4837         }
4838         else
4839         {
4840                 // merge mins/maxs when we're adding this surface to the plane
4841                 p = r_fb.water.waterplanes + planeindex;
4842                 p->mins[0] = min(p->mins[0], mins[0]);
4843                 p->mins[1] = min(p->mins[1], mins[1]);
4844                 p->mins[2] = min(p->mins[2], mins[2]);
4845                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4846                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4847                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4848         }
4849         // merge this surface's materialflags into the waterplane
4850         p->materialflags |= t->currentmaterialflags;
4851         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4852         {
4853                 // merge this surface's PVS into the waterplane
4854                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4855                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4856                 {
4857                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4858                         p->pvsvalid = true;
4859                 }
4860         }
4861 }
4862
4863 extern cvar_t r_drawparticles;
4864 extern cvar_t r_drawdecals;
4865
4866 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4867 {
4868         int myscissor[4];
4869         r_refdef_view_t originalview;
4870         r_refdef_view_t myview;
4871         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;
4872         r_waterstate_waterplane_t *p;
4873         vec3_t visorigin;
4874         r_rendertarget_t *rt;
4875
4876         originalview = r_refdef.view;
4877
4878         // lowquality hack, temporarily shut down some cvars and restore afterwards
4879         qualityreduction = r_water_lowquality.integer;
4880         if (qualityreduction > 0)
4881         {
4882                 if (qualityreduction >= 1)
4883                 {
4884                         old_r_shadows = r_shadows.integer;
4885                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4886                         old_r_dlight = r_shadow_realtime_dlight.integer;
4887                         Cvar_SetValueQuick(&r_shadows, 0);
4888                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4889                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4890                 }
4891                 if (qualityreduction >= 2)
4892                 {
4893                         old_r_dynamic = r_dynamic.integer;
4894                         old_r_particles = r_drawparticles.integer;
4895                         old_r_decals = r_drawdecals.integer;
4896                         Cvar_SetValueQuick(&r_dynamic, 0);
4897                         Cvar_SetValueQuick(&r_drawparticles, 0);
4898                         Cvar_SetValueQuick(&r_drawdecals, 0);
4899                 }
4900         }
4901
4902         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4903         {
4904                 p->rt_reflection = NULL;
4905                 p->rt_refraction = NULL;
4906                 p->rt_camera = NULL;
4907         }
4908
4909         // render views
4910         r_refdef.view = originalview;
4911         r_refdef.view.showdebug = false;
4912         r_refdef.view.width = r_fb.water.waterwidth;
4913         r_refdef.view.height = r_fb.water.waterheight;
4914         r_refdef.view.useclipplane = true;
4915         myview = r_refdef.view;
4916         r_fb.water.renderingscene = true;
4917         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4918         {
4919                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4920                         continue;
4921
4922                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4923                 {
4924                         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);
4925                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4926                                 goto error;
4927                         r_refdef.view = myview;
4928                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4929                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4930                         if(r_water_scissormode.integer)
4931                         {
4932                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4933                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4934                                 {
4935                                         p->rt_reflection = NULL;
4936                                         p->rt_refraction = NULL;
4937                                         p->rt_camera = NULL;
4938                                         continue;
4939                                 }
4940                         }
4941
4942                         r_refdef.view.clipplane = p->plane;
4943                         // reflected view origin may be in solid, so don't cull with it
4944                         r_refdef.view.usevieworiginculling = false;
4945                         // reverse the cullface settings for this render
4946                         r_refdef.view.cullface_front = GL_FRONT;
4947                         r_refdef.view.cullface_back = GL_BACK;
4948                         // combined pvs (based on what can be seen from each surface center)
4949                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4950                         {
4951                                 r_refdef.view.usecustompvs = true;
4952                                 if (p->pvsvalid)
4953                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4954                                 else
4955                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4956                         }
4957
4958                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4959                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4960                         GL_ScissorTest(false);
4961                         R_ClearScreen(r_refdef.fogenabled);
4962                         GL_ScissorTest(true);
4963                         if(r_water_scissormode.integer & 2)
4964                                 R_View_UpdateWithScissor(myscissor);
4965                         else
4966                                 R_View_Update();
4967                         R_AnimCache_CacheVisibleEntities();
4968                         if(r_water_scissormode.integer & 1)
4969                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4970                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4971
4972                         r_fb.water.hideplayer = false;
4973                         p->rt_reflection = rt;
4974                 }
4975
4976                 // render the normal view scene and copy into texture
4977                 // (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)
4978                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4979                 {
4980                         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);
4981                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4982                                 goto error;
4983                         r_refdef.view = myview;
4984                         if(r_water_scissormode.integer)
4985                         {
4986                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4987                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4988                                 {
4989                                         p->rt_reflection = NULL;
4990                                         p->rt_refraction = NULL;
4991                                         p->rt_camera = NULL;
4992                                         continue;
4993                                 }
4994                         }
4995
4996                         // combined pvs (based on what can be seen from each surface center)
4997                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4998                         {
4999                                 r_refdef.view.usecustompvs = true;
5000                                 if (p->pvsvalid)
5001                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5002                                 else
5003                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5004                         }
5005
5006                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5007
5008                         r_refdef.view.clipplane = p->plane;
5009                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5010                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5011
5012                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5013                         {
5014                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5015                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5016                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5017                                 R_RenderView_UpdateViewVectors();
5018                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5019                                 {
5020                                         r_refdef.view.usecustompvs = true;
5021                                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
5022                                 }
5023                         }
5024
5025                         PlaneClassify(&r_refdef.view.clipplane);
5026
5027                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5028                         GL_ScissorTest(false);
5029                         R_ClearScreen(r_refdef.fogenabled);
5030                         GL_ScissorTest(true);
5031                         if(r_water_scissormode.integer & 2)
5032                                 R_View_UpdateWithScissor(myscissor);
5033                         else
5034                                 R_View_Update();
5035                         R_AnimCache_CacheVisibleEntities();
5036                         if(r_water_scissormode.integer & 1)
5037                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5038                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5039
5040                         r_fb.water.hideplayer = false;
5041                         p->rt_refraction = rt;
5042                 }
5043                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5044                 {
5045                         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);
5046                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5047                                 goto error;
5048                         r_refdef.view = myview;
5049
5050                         r_refdef.view.clipplane = p->plane;
5051                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5052                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5053
5054                         r_refdef.view.width = r_fb.water.camerawidth;
5055                         r_refdef.view.height = r_fb.water.cameraheight;
5056                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5057                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5058                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5059                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5060
5061                         if(p->camera_entity)
5062                         {
5063                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5064                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5065                         }
5066
5067                         // note: all of the view is used for displaying... so
5068                         // there is no use in scissoring
5069
5070                         // reverse the cullface settings for this render
5071                         r_refdef.view.cullface_front = GL_FRONT;
5072                         r_refdef.view.cullface_back = GL_BACK;
5073                         // also reverse the view matrix
5074                         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
5075                         R_RenderView_UpdateViewVectors();
5076                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5077                         {
5078                                 r_refdef.view.usecustompvs = true;
5079                                 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
5080                         }
5081                         
5082                         // camera needs no clipplane
5083                         r_refdef.view.useclipplane = false;
5084                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5085                         r_refdef.view.usevieworiginculling = false;
5086
5087                         PlaneClassify(&r_refdef.view.clipplane);
5088
5089                         r_fb.water.hideplayer = false;
5090
5091                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5092                         GL_ScissorTest(false);
5093                         R_ClearScreen(r_refdef.fogenabled);
5094                         GL_ScissorTest(true);
5095                         R_View_Update();
5096                         R_AnimCache_CacheVisibleEntities();
5097                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5098
5099                         r_fb.water.hideplayer = false;
5100                         p->rt_camera = rt;
5101                 }
5102
5103         }
5104         r_fb.water.renderingscene = false;
5105         r_refdef.view = originalview;
5106         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5107         R_View_Update();
5108         R_AnimCache_CacheVisibleEntities();
5109         goto finish;
5110 error:
5111         r_refdef.view = originalview;
5112         r_fb.water.renderingscene = false;
5113         Cvar_SetValueQuick(&r_water, 0);
5114         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5115 finish:
5116         // lowquality hack, restore cvars
5117         if (qualityreduction > 0)
5118         {
5119                 if (qualityreduction >= 1)
5120                 {
5121                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5122                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5123                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5124                 }
5125                 if (qualityreduction >= 2)
5126                 {
5127                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5128                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5129                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5130                 }
5131         }
5132 }
5133
5134 static void R_Bloom_StartFrame(void)
5135 {
5136         int screentexturewidth, screentextureheight;
5137         textype_t textype = TEXTYPE_COLORBUFFER;
5138         double scale;
5139
5140         // clear the pointers to rendertargets from last frame as they're stale
5141         r_fb.rt_screen = NULL;
5142         r_fb.rt_bloom = NULL;
5143
5144         switch (vid.renderpath)
5145         {
5146         case RENDERPATH_GL32:
5147                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5148                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5149                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5150                 break;
5151         case RENDERPATH_GLES2:
5152                 r_fb.usedepthtextures = false;
5153                 break;
5154         }
5155
5156         if (r_viewscale_fpsscaling.integer)
5157         {
5158                 double actualframetime;
5159                 double targetframetime;
5160                 double adjust;
5161                 actualframetime = r_refdef.lastdrawscreentime;
5162                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5163                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5164                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5165                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5166                 {
5167                         if (adjust > 0)
5168                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5169                         else
5170                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5171                 }
5172                 viewscalefpsadjusted += adjust;
5173                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5174         }
5175         else
5176                 viewscalefpsadjusted = 1.0f;
5177
5178         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5179         if (vid.samples)
5180                 scale *= sqrt(vid.samples); // supersampling
5181         scale = bound(0.03125f, scale, 4.0f);
5182         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5183         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5184         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5185         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5186
5187         // set bloomwidth and bloomheight to the bloom resolution that will be
5188         // used (often less than the screen resolution for faster rendering)
5189         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5190         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5191         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5192         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5193         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5194
5195         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))
5196         {
5197                 Cvar_SetValueQuick(&r_bloom, 0);
5198                 Cvar_SetValueQuick(&r_motionblur, 0);
5199                 Cvar_SetValueQuick(&r_damageblur, 0);
5200         }
5201         if (!r_bloom.integer)
5202                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5203
5204         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5205         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5206         {
5207                 if (r_fb.ghosttexture)
5208                         R_FreeTexture(r_fb.ghosttexture);
5209                 r_fb.ghosttexture = NULL;
5210
5211                 r_fb.screentexturewidth = screentexturewidth;
5212                 r_fb.screentextureheight = screentextureheight;
5213                 r_fb.textype = textype;
5214
5215                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5216                 {
5217                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5218                                 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);
5219                         r_fb.ghosttexture_valid = false;
5220                 }
5221         }
5222
5223         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5224
5225         r_refdef.view.clear = true;
5226 }
5227
5228 static void R_Bloom_MakeTexture(void)
5229 {
5230         int x, range, dir;
5231         float xoffset, yoffset, r, brighten;
5232         float colorscale = r_bloom_colorscale.value;
5233         r_viewport_t bloomviewport;
5234         r_rendertarget_t *prev, *cur;
5235         textype_t textype = r_fb.rt_screen->colortextype[0];
5236
5237         r_refdef.stats[r_stat_bloom]++;
5238
5239         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5240
5241         // scale down screen texture to the bloom texture size
5242         CHECKGLERROR
5243         prev = r_fb.rt_screen;
5244         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5245         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5246         R_SetViewport(&bloomviewport);
5247         GL_CullFace(GL_NONE);
5248         GL_DepthTest(false);
5249         GL_BlendFunc(GL_ONE, GL_ZERO);
5250         GL_Color(colorscale, colorscale, colorscale, 1);
5251         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5252         // TODO: do boxfilter scale-down in shader?
5253         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5254         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5255         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5256         // we now have a properly scaled bloom image
5257
5258         // multiply bloom image by itself as many times as desired to darken it
5259         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5260         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5261         {
5262                 prev = cur;
5263                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5264                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5265                 x *= 2;
5266                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5267                 if(x <= 2)
5268                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5269                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5270                 GL_Color(1,1,1,1); // no fix factor supported here
5271                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5272                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5273                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5274                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5275         }
5276         CHECKGLERROR
5277
5278         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5279         brighten = r_bloom_brighten.value;
5280         brighten = sqrt(brighten);
5281         if(range >= 1)
5282                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5283
5284         for (dir = 0;dir < 2;dir++)
5285         {
5286                 prev = cur;
5287                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5288                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5289                 // blend on at multiple vertical offsets to achieve a vertical blur
5290                 // TODO: do offset blends using GLSL
5291                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5292                 CHECKGLERROR
5293                 GL_BlendFunc(GL_ONE, GL_ZERO);
5294                 CHECKGLERROR
5295                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5296                 CHECKGLERROR
5297                 for (x = -range;x <= range;x++)
5298                 {
5299                         if (!dir){xoffset = 0;yoffset = x;}
5300                         else {xoffset = x;yoffset = 0;}
5301                         xoffset /= (float)prev->texturewidth;
5302                         yoffset /= (float)prev->textureheight;
5303                         // compute a texcoord array with the specified x and y offset
5304                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5305                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5306                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5307                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5308                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5309                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5310                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5311                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5312                         // this r value looks like a 'dot' particle, fading sharply to
5313                         // black at the edges
5314                         // (probably not realistic but looks good enough)
5315                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5316                         //r = brighten/(range*2+1);
5317                         r = brighten / (range * 2 + 1);
5318                         if(range >= 1)
5319                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5320                         if (r <= 0)
5321                                 continue;
5322                         CHECKGLERROR
5323                         GL_Color(r, r, r, 1);
5324                         CHECKGLERROR
5325                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5326                         CHECKGLERROR
5327                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5328                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5329                         CHECKGLERROR
5330                         GL_BlendFunc(GL_ONE, GL_ONE);
5331                         CHECKGLERROR
5332                 }
5333         }
5334
5335         // now we have the bloom image, so keep track of it
5336         r_fb.rt_bloom = cur;
5337 }
5338
5339 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5340 {
5341         uint64_t permutation;
5342         float uservecs[4][4];
5343         rtexture_t *viewtexture;
5344         rtexture_t *bloomtexture;
5345
5346         R_EntityMatrix(&identitymatrix);
5347
5348         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5349         {
5350                 // declare variables
5351                 float blur_factor, blur_mouseaccel, blur_velocity;
5352                 static float blur_average; 
5353                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5354
5355                 // set a goal for the factoring
5356                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5357                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5358                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5359                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5360                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5361                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5362
5363                 // from the goal, pick an averaged value between goal and last value
5364                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5365                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5366
5367                 // enforce minimum amount of blur 
5368                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5369
5370                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5371
5372                 // calculate values into a standard alpha
5373                 cl.motionbluralpha = 1 - exp(-
5374                                 (
5375                                         (r_motionblur.value * blur_factor / 80)
5376                                         +
5377                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5378                                 )
5379                                 /
5380                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5381                                 );
5382
5383                 // randomization for the blur value to combat persistent ghosting
5384                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5385                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5386
5387                 // apply the blur
5388                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5389                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5390                 {
5391                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5392                         GL_Color(1, 1, 1, cl.motionbluralpha);
5393                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5394                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5395                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5396                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5397                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5398                 }
5399
5400                 // updates old view angles for next pass
5401                 VectorCopy(cl.viewangles, blur_oldangles);
5402
5403                 // copy view into the ghost texture
5404                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5405                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5406                 r_fb.ghosttexture_valid = true;
5407         }
5408
5409         if (r_fb.bloomwidth)
5410         {
5411                 // make the bloom texture
5412                 R_Bloom_MakeTexture();
5413         }
5414
5415 #if _MSC_VER >= 1400
5416 #define sscanf sscanf_s
5417 #endif
5418         memset(uservecs, 0, sizeof(uservecs));
5419         if (r_glsl_postprocess_uservec1_enable.integer)
5420                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5421         if (r_glsl_postprocess_uservec2_enable.integer)
5422                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5423         if (r_glsl_postprocess_uservec3_enable.integer)
5424                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5425         if (r_glsl_postprocess_uservec4_enable.integer)
5426                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5427
5428         // render to the screen fbo
5429         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5430         GL_Color(1, 1, 1, 1);
5431         GL_BlendFunc(GL_ONE, GL_ZERO);
5432
5433         viewtexture = r_fb.rt_screen->colortexture[0];
5434         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5435
5436         if (r_rendertarget_debug.integer >= 0)
5437         {
5438                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5439                 if (rt && rt->colortexture[0])
5440                 {
5441                         viewtexture = rt->colortexture[0];
5442                         bloomtexture = NULL;
5443                 }
5444         }
5445
5446         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5447         switch(vid.renderpath)
5448         {
5449         case RENDERPATH_GL32:
5450         case RENDERPATH_GLES2:
5451                 permutation =
5452                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5453                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5454                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5455                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5456                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5457                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5458                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5459                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5460                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5461                 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]);
5462                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5463                 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]);
5464                 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]);
5465                 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]);
5466                 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]);
5467                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5468                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5469                 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);
5470                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5471                 break;
5472         }
5473         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5474         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5475 }
5476
5477 matrix4x4_t r_waterscrollmatrix;
5478
5479 void R_UpdateFog(void)
5480 {
5481         // Nehahra fog
5482         if (gamemode == GAME_NEHAHRA)
5483         {
5484                 if (gl_fogenable.integer)
5485                 {
5486                         r_refdef.oldgl_fogenable = true;
5487                         r_refdef.fog_density = gl_fogdensity.value;
5488                         r_refdef.fog_red = gl_fogred.value;
5489                         r_refdef.fog_green = gl_foggreen.value;
5490                         r_refdef.fog_blue = gl_fogblue.value;
5491                         r_refdef.fog_alpha = 1;
5492                         r_refdef.fog_start = 0;
5493                         r_refdef.fog_end = gl_skyclip.value;
5494                         r_refdef.fog_height = 1<<30;
5495                         r_refdef.fog_fadedepth = 128;
5496                 }
5497                 else if (r_refdef.oldgl_fogenable)
5498                 {
5499                         r_refdef.oldgl_fogenable = false;
5500                         r_refdef.fog_density = 0;
5501                         r_refdef.fog_red = 0;
5502                         r_refdef.fog_green = 0;
5503                         r_refdef.fog_blue = 0;
5504                         r_refdef.fog_alpha = 0;
5505                         r_refdef.fog_start = 0;
5506                         r_refdef.fog_end = 0;
5507                         r_refdef.fog_height = 1<<30;
5508                         r_refdef.fog_fadedepth = 128;
5509                 }
5510         }
5511
5512         // fog parms
5513         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5514         r_refdef.fog_start = max(0, r_refdef.fog_start);
5515         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5516
5517         if (r_refdef.fog_density && r_drawfog.integer)
5518         {
5519                 r_refdef.fogenabled = true;
5520                 // this is the point where the fog reaches 0.9986 alpha, which we
5521                 // consider a good enough cutoff point for the texture
5522                 // (0.9986 * 256 == 255.6)
5523                 if (r_fog_exp2.integer)
5524                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5525                 else
5526                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5527                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5528                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5529                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5530                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5531                         R_BuildFogHeightTexture();
5532                 // fog color was already set
5533                 // update the fog texture
5534                 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)
5535                         R_BuildFogTexture();
5536                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5537                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5538         }
5539         else
5540                 r_refdef.fogenabled = false;
5541
5542         // fog color
5543         if (r_refdef.fog_density)
5544         {
5545                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5546                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5547                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5548
5549                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5550                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5551                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5552                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5553
5554                 {
5555                         vec3_t fogvec;
5556                         VectorCopy(r_refdef.fogcolor, fogvec);
5557                         //   color.rgb *= ContrastBoost * SceneBrightness;
5558                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5559                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5560                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5561                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5562                 }
5563         }
5564 }
5565
5566 void R_UpdateVariables(void)
5567 {
5568         R_Textures_Frame();
5569
5570         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5571
5572         r_refdef.farclip = r_farclip_base.value;
5573         if (r_refdef.scene.worldmodel)
5574                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5575         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5576
5577         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5578                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5579         r_refdef.polygonfactor = 0;
5580         r_refdef.polygonoffset = 0;
5581
5582         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5583         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5584         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5585         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5586         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5587         if (r_refdef.scene.worldmodel)
5588         {
5589                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5590         }
5591         if (r_showsurfaces.integer)
5592         {
5593                 r_refdef.scene.rtworld = false;
5594                 r_refdef.scene.rtworldshadows = false;
5595                 r_refdef.scene.rtdlight = false;
5596                 r_refdef.scene.rtdlightshadows = false;
5597                 r_refdef.scene.lightmapintensity = 0;
5598         }
5599
5600         r_gpuskeletal = false;
5601         switch(vid.renderpath)
5602         {
5603         case RENDERPATH_GL32:
5604                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5605         case RENDERPATH_GLES2:
5606                 if(!vid_gammatables_trivial)
5607                 {
5608                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5609                         {
5610                                 // build GLSL gamma texture
5611 #define RAMPWIDTH 256
5612                                 unsigned short ramp[RAMPWIDTH * 3];
5613                                 unsigned char rampbgr[RAMPWIDTH][4];
5614                                 int i;
5615
5616                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5617
5618                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5619                                 for(i = 0; i < RAMPWIDTH; ++i)
5620                                 {
5621                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5622                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5623                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5624                                         rampbgr[i][3] = 0;
5625                                 }
5626                                 if (r_texture_gammaramps)
5627                                 {
5628                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5629                                 }
5630                                 else
5631                                 {
5632                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5633                                 }
5634                         }
5635                 }
5636                 else
5637                 {
5638                         // remove GLSL gamma texture
5639                 }
5640                 break;
5641         }
5642 }
5643
5644 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5645 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5646 /*
5647 ================
5648 R_SelectScene
5649 ================
5650 */
5651 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5652         if( scenetype != r_currentscenetype ) {
5653                 // store the old scenetype
5654                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5655                 r_currentscenetype = scenetype;
5656                 // move in the new scene
5657                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5658         }
5659 }
5660
5661 /*
5662 ================
5663 R_GetScenePointer
5664 ================
5665 */
5666 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5667 {
5668         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5669         if( scenetype == r_currentscenetype ) {
5670                 return &r_refdef.scene;
5671         } else {
5672                 return &r_scenes_store[ scenetype ];
5673         }
5674 }
5675
5676 static int R_SortEntities_Compare(const void *ap, const void *bp)
5677 {
5678         const entity_render_t *a = *(const entity_render_t **)ap;
5679         const entity_render_t *b = *(const entity_render_t **)bp;
5680
5681         // 1. compare model
5682         if(a->model < b->model)
5683                 return -1;
5684         if(a->model > b->model)
5685                 return +1;
5686
5687         // 2. compare skin
5688         // TODO possibly calculate the REAL skinnum here first using
5689         // skinscenes?
5690         if(a->skinnum < b->skinnum)
5691                 return -1;
5692         if(a->skinnum > b->skinnum)
5693                 return +1;
5694
5695         // everything we compared is equal
5696         return 0;
5697 }
5698 static void R_SortEntities(void)
5699 {
5700         // below or equal 2 ents, sorting never gains anything
5701         if(r_refdef.scene.numentities <= 2)
5702                 return;
5703         // sort
5704         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5705 }
5706
5707 /*
5708 ================
5709 R_RenderView
5710 ================
5711 */
5712 extern cvar_t r_shadow_bouncegrid;
5713 extern cvar_t v_isometric;
5714 extern void V_MakeViewIsometric(void);
5715 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5716 {
5717         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5718         int viewfbo = 0;
5719         rtexture_t *viewdepthtexture = NULL;
5720         rtexture_t *viewcolortexture = NULL;
5721         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5722
5723         // finish any 2D rendering that was queued
5724         DrawQ_Finish();
5725
5726         if (r_timereport_active)
5727                 R_TimeReport("start");
5728         r_textureframe++; // used only by R_GetCurrentTexture
5729         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5730
5731         if(R_CompileShader_CheckStaticParms())
5732                 R_GLSL_Restart_f(&cmd_client);
5733
5734         if (!r_drawentities.integer)
5735                 r_refdef.scene.numentities = 0;
5736         else if (r_sortentities.integer)
5737                 R_SortEntities();
5738
5739         R_AnimCache_ClearCache();
5740
5741         /* adjust for stereo display */
5742         if(R_Stereo_Active())
5743         {
5744                 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);
5745                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5746         }
5747
5748         if (r_refdef.view.isoverlay)
5749         {
5750                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5751                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5752                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5753                 R_TimeReport("depthclear");
5754
5755                 r_refdef.view.showdebug = false;
5756
5757                 r_fb.water.enabled = false;
5758                 r_fb.water.numwaterplanes = 0;
5759
5760                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5761
5762                 r_refdef.view.matrix = originalmatrix;
5763
5764                 CHECKGLERROR
5765                 return;
5766         }
5767
5768         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5769         {
5770                 r_refdef.view.matrix = originalmatrix;
5771                 return;
5772         }
5773
5774         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5775         if (v_isometric.integer && r_refdef.view.ismain)
5776                 V_MakeViewIsometric();
5777
5778         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5779
5780         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5781                 // in sRGB fallback, behave similar to true sRGB: convert this
5782                 // value from linear to sRGB
5783                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5784
5785         R_RenderView_UpdateViewVectors();
5786
5787         R_Shadow_UpdateWorldLightSelection();
5788
5789         // this will set up r_fb.rt_screen
5790         R_Bloom_StartFrame();
5791
5792         // apply bloom brightness offset
5793         if(r_fb.rt_bloom)
5794                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5795
5796         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5797         if (r_fb.rt_screen)
5798         {
5799                 viewfbo = r_fb.rt_screen->fbo;
5800                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5801                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5802                 viewx = 0;
5803                 viewy = 0;
5804                 viewwidth = r_fb.rt_screen->texturewidth;
5805                 viewheight = r_fb.rt_screen->textureheight;
5806         }
5807
5808         R_Water_StartFrame(viewwidth, viewheight);
5809
5810         CHECKGLERROR
5811         if (r_timereport_active)
5812                 R_TimeReport("viewsetup");
5813
5814         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5815
5816         // clear the whole fbo every frame - otherwise the driver will consider
5817         // it to be an inter-frame texture and stall in multi-gpu configurations
5818         if (r_fb.rt_screen)
5819                 GL_ScissorTest(false);
5820         R_ClearScreen(r_refdef.fogenabled);
5821         if (r_timereport_active)
5822                 R_TimeReport("viewclear");
5823
5824         r_refdef.view.clear = true;
5825
5826         r_refdef.view.showdebug = true;
5827
5828         R_View_Update();
5829         if (r_timereport_active)
5830                 R_TimeReport("visibility");
5831
5832         R_AnimCache_CacheVisibleEntities();
5833         if (r_timereport_active)
5834                 R_TimeReport("animcache");
5835
5836         R_Shadow_UpdateBounceGridTexture();
5837         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5838
5839         r_fb.water.numwaterplanes = 0;
5840         if (r_fb.water.enabled)
5841                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5842
5843         // for the actual view render we use scissoring a fair amount, so scissor
5844         // test needs to be on
5845         if (r_fb.rt_screen)
5846                 GL_ScissorTest(true);
5847         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5848         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5849         r_fb.water.numwaterplanes = 0;
5850
5851         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5852         GL_ScissorTest(false);
5853
5854         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5855         if (r_timereport_active)
5856                 R_TimeReport("blendview");
5857
5858         r_refdef.view.matrix = originalmatrix;
5859
5860         CHECKGLERROR
5861
5862         // go back to 2d rendering
5863         DrawQ_Start();
5864 }
5865
5866 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5867 {
5868         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5869         {
5870                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5871                 if (r_timereport_active)
5872                         R_TimeReport("waterworld");
5873         }
5874
5875         // don't let sound skip if going slow
5876         if (r_refdef.scene.extraupdate)
5877                 S_ExtraUpdate ();
5878
5879         R_DrawModelsAddWaterPlanes();
5880         if (r_timereport_active)
5881                 R_TimeReport("watermodels");
5882
5883         if (r_fb.water.numwaterplanes)
5884         {
5885                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5886                 if (r_timereport_active)
5887                         R_TimeReport("waterscenes");
5888         }
5889 }
5890
5891 extern cvar_t cl_locs_show;
5892 static void R_DrawLocs(void);
5893 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5894 static void R_DrawModelDecals(void);
5895 extern qboolean r_shadow_usingdeferredprepass;
5896 extern int r_shadow_shadowmapatlas_modelshadows_size;
5897 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5898 {
5899         qboolean shadowmapping = false;
5900
5901         if (r_timereport_active)
5902                 R_TimeReport("beginscene");
5903
5904         r_refdef.stats[r_stat_renders]++;
5905
5906         R_UpdateFog();
5907
5908         // don't let sound skip if going slow
5909         if (r_refdef.scene.extraupdate)
5910                 S_ExtraUpdate ();
5911
5912         R_MeshQueue_BeginScene();
5913
5914         R_SkyStartFrame();
5915
5916         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);
5917
5918         if (r_timereport_active)
5919                 R_TimeReport("skystartframe");
5920
5921         if (cl.csqc_vidvars.drawworld)
5922         {
5923                 // don't let sound skip if going slow
5924                 if (r_refdef.scene.extraupdate)
5925                         S_ExtraUpdate ();
5926
5927                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5928                 {
5929                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5930                         if (r_timereport_active)
5931                                 R_TimeReport("worldsky");
5932                 }
5933
5934                 if (R_DrawBrushModelsSky() && r_timereport_active)
5935                         R_TimeReport("bmodelsky");
5936
5937                 if (skyrendermasked && skyrenderlater)
5938                 {
5939                         // we have to force off the water clipping plane while rendering sky
5940                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5941                         R_Sky();
5942                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5943                         if (r_timereport_active)
5944                                 R_TimeReport("sky");
5945                 }
5946         }
5947
5948         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5949         r_shadow_viewfbo = viewfbo;
5950         r_shadow_viewdepthtexture = viewdepthtexture;
5951         r_shadow_viewcolortexture = viewcolortexture;
5952         r_shadow_viewx = viewx;
5953         r_shadow_viewy = viewy;
5954         r_shadow_viewwidth = viewwidth;
5955         r_shadow_viewheight = viewheight;
5956
5957         R_Shadow_PrepareModelShadows();
5958         R_Shadow_PrepareLights();
5959         if (r_timereport_active)
5960                 R_TimeReport("preparelights");
5961
5962         // render all the shadowmaps that will be used for this view
5963         shadowmapping = R_Shadow_ShadowMappingEnabled();
5964         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5965         {
5966                 R_Shadow_DrawShadowMaps();
5967                 if (r_timereport_active)
5968                         R_TimeReport("shadowmaps");
5969         }
5970
5971         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5972         if (r_shadow_usingdeferredprepass)
5973                 R_Shadow_DrawPrepass();
5974
5975         // now we begin the forward pass of the view render
5976         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5977         {
5978                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5979                 if (r_timereport_active)
5980                         R_TimeReport("worlddepth");
5981         }
5982         if (r_depthfirst.integer >= 2)
5983         {
5984                 R_DrawModelsDepth();
5985                 if (r_timereport_active)
5986                         R_TimeReport("modeldepth");
5987         }
5988
5989         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5990         {
5991                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5992                 if (r_timereport_active)
5993                         R_TimeReport("world");
5994         }
5995
5996         // don't let sound skip if going slow
5997         if (r_refdef.scene.extraupdate)
5998                 S_ExtraUpdate ();
5999
6000         R_DrawModels();
6001         if (r_timereport_active)
6002                 R_TimeReport("models");
6003
6004         // don't let sound skip if going slow
6005         if (r_refdef.scene.extraupdate)
6006                 S_ExtraUpdate ();
6007
6008         if (!r_shadow_usingdeferredprepass)
6009         {
6010                 R_Shadow_DrawLights();
6011                 if (r_timereport_active)
6012                         R_TimeReport("rtlights");
6013         }
6014
6015         // don't let sound skip if going slow
6016         if (r_refdef.scene.extraupdate)
6017                 S_ExtraUpdate ();
6018
6019         if (cl.csqc_vidvars.drawworld)
6020         {
6021                 R_DrawModelDecals();
6022                 if (r_timereport_active)
6023                         R_TimeReport("modeldecals");
6024
6025                 R_DrawParticles();
6026                 if (r_timereport_active)
6027                         R_TimeReport("particles");
6028
6029                 R_DrawExplosions();
6030                 if (r_timereport_active)
6031                         R_TimeReport("explosions");
6032         }
6033
6034         if (r_refdef.view.showdebug)
6035         {
6036                 if (cl_locs_show.integer)
6037                 {
6038                         R_DrawLocs();
6039                         if (r_timereport_active)
6040                                 R_TimeReport("showlocs");
6041                 }
6042
6043                 if (r_drawportals.integer)
6044                 {
6045                         R_DrawPortals();
6046                         if (r_timereport_active)
6047                                 R_TimeReport("portals");
6048                 }
6049
6050                 if (r_showbboxes_client.value > 0)
6051                 {
6052                         R_DrawEntityBBoxes(CLVM_prog);
6053                         if (r_timereport_active)
6054                                 R_TimeReport("clbboxes");
6055                 }
6056                 if (r_showbboxes.value > 0)
6057                 {
6058                         R_DrawEntityBBoxes(SVVM_prog);
6059                         if (r_timereport_active)
6060                                 R_TimeReport("svbboxes");
6061                 }
6062         }
6063
6064         if (r_transparent.integer)
6065         {
6066                 R_MeshQueue_RenderTransparent();
6067                 if (r_timereport_active)
6068                         R_TimeReport("drawtrans");
6069         }
6070
6071         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))
6072         {
6073                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6074                 if (r_timereport_active)
6075                         R_TimeReport("worlddebug");
6076                 R_DrawModelsDebug();
6077                 if (r_timereport_active)
6078                         R_TimeReport("modeldebug");
6079         }
6080
6081         if (cl.csqc_vidvars.drawworld)
6082         {
6083                 R_Shadow_DrawCoronas();
6084                 if (r_timereport_active)
6085                         R_TimeReport("coronas");
6086         }
6087
6088         // don't let sound skip if going slow
6089         if (r_refdef.scene.extraupdate)
6090                 S_ExtraUpdate ();
6091 }
6092
6093 static const unsigned short bboxelements[36] =
6094 {
6095         5, 1, 3, 5, 3, 7,
6096         6, 2, 0, 6, 0, 4,
6097         7, 3, 2, 7, 2, 6,
6098         4, 0, 1, 4, 1, 5,
6099         4, 5, 7, 4, 7, 6,
6100         1, 0, 2, 1, 2, 3,
6101 };
6102
6103 #define BBOXEDGES 13
6104 static const float bboxedges[BBOXEDGES][6] = 
6105 {
6106         // whole box
6107         { 0, 0, 0, 1, 1, 1 },
6108         // bottom edges
6109         { 0, 0, 0, 0, 1, 0 },
6110         { 0, 0, 0, 1, 0, 0 },
6111         { 0, 1, 0, 1, 1, 0 },
6112         { 1, 0, 0, 1, 1, 0 },
6113         // top edges
6114         { 0, 0, 1, 0, 1, 1 },
6115         { 0, 0, 1, 1, 0, 1 },
6116         { 0, 1, 1, 1, 1, 1 },
6117         { 1, 0, 1, 1, 1, 1 },
6118         // vertical edges
6119         { 0, 0, 0, 0, 0, 1 },
6120         { 1, 0, 0, 1, 0, 1 },
6121         { 0, 1, 0, 0, 1, 1 },
6122         { 1, 1, 0, 1, 1, 1 },
6123 };
6124
6125 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6126 {
6127         int numvertices = BBOXEDGES * 8;
6128         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6129         int numtriangles = BBOXEDGES * 12;
6130         unsigned short elements[BBOXEDGES * 36];
6131         int i, edge;
6132         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6133
6134         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6135
6136         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6137         GL_DepthMask(false);
6138         GL_DepthRange(0, 1);
6139         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6140
6141         for (edge = 0; edge < BBOXEDGES; edge++)
6142         {
6143                 for (i = 0; i < 3; i++)
6144                 {
6145                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6146                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6147                 }
6148                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6149                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6150                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6151                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6152                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6153                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6154                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6155                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6156                 for (i = 0; i < 36; i++)
6157                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6158         }
6159         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6160         if (r_refdef.fogenabled)
6161         {
6162                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6163                 {
6164                         f1 = RSurf_FogVertex(v);
6165                         f2 = 1 - f1;
6166                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6167                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6168                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6169                 }
6170         }
6171         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6172         R_Mesh_ResetTextureState();
6173         R_SetupShader_Generic_NoTexture(false, false);
6174         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6175 }
6176
6177 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6178 {
6179         // hacky overloading of the parameters
6180         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6181         int i;
6182         float color[4];
6183         prvm_edict_t *edict;
6184
6185         GL_CullFace(GL_NONE);
6186         R_SetupShader_Generic_NoTexture(false, false);
6187
6188         for (i = 0;i < numsurfaces;i++)
6189         {
6190                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6191                 switch ((int)PRVM_serveredictfloat(edict, solid))
6192                 {
6193                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6194                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6195                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6196                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6197                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6198                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6199                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6200                 }
6201                 if (prog == CLVM_prog)
6202                         color[3] *= r_showbboxes_client.value;
6203                 else
6204                         color[3] *= r_showbboxes.value;
6205                 color[3] = bound(0, color[3], 1);
6206                 GL_DepthTest(!r_showdisabledepthtest.integer);
6207                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6208         }
6209 }
6210
6211 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6212 {
6213         int i;
6214         prvm_edict_t *edict;
6215         vec3_t center;
6216
6217         if (prog == NULL)
6218                 return;
6219
6220         for (i = 0; i < prog->num_edicts; i++)
6221         {
6222                 edict = PRVM_EDICT_NUM(i);
6223                 if (edict->priv.server->free)
6224                         continue;
6225                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6226                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6227                         continue;
6228                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6229                         continue;
6230                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6231                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6232         }
6233 }
6234
6235 static const int nomodelelement3i[24] =
6236 {
6237         5, 2, 0,
6238         5, 1, 2,
6239         5, 0, 3,
6240         5, 3, 1,
6241         0, 2, 4,
6242         2, 1, 4,
6243         3, 0, 4,
6244         1, 3, 4
6245 };
6246
6247 static const unsigned short nomodelelement3s[24] =
6248 {
6249         5, 2, 0,
6250         5, 1, 2,
6251         5, 0, 3,
6252         5, 3, 1,
6253         0, 2, 4,
6254         2, 1, 4,
6255         3, 0, 4,
6256         1, 3, 4
6257 };
6258
6259 static const float nomodelvertex3f[6*3] =
6260 {
6261         -16,   0,   0,
6262          16,   0,   0,
6263           0, -16,   0,
6264           0,  16,   0,
6265           0,   0, -16,
6266           0,   0,  16
6267 };
6268
6269 static const float nomodelcolor4f[6*4] =
6270 {
6271         0.0f, 0.0f, 0.5f, 1.0f,
6272         0.0f, 0.0f, 0.5f, 1.0f,
6273         0.0f, 0.5f, 0.0f, 1.0f,
6274         0.0f, 0.5f, 0.0f, 1.0f,
6275         0.5f, 0.0f, 0.0f, 1.0f,
6276         0.5f, 0.0f, 0.0f, 1.0f
6277 };
6278
6279 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6280 {
6281         int i;
6282         float f1, f2, *c;
6283         float color4f[6*4];
6284
6285         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);
6286
6287         // this is only called once per entity so numsurfaces is always 1, and
6288         // surfacelist is always {0}, so this code does not handle batches
6289
6290         if (rsurface.ent_flags & RENDER_ADDITIVE)
6291         {
6292                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6293                 GL_DepthMask(false);
6294         }
6295         else if (ent->alpha < 1)
6296         {
6297                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6298                 GL_DepthMask(false);
6299         }
6300         else
6301         {
6302                 GL_BlendFunc(GL_ONE, GL_ZERO);
6303                 GL_DepthMask(true);
6304         }
6305         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6306         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6307         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6308         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6309         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6310         for (i = 0, c = color4f;i < 6;i++, c += 4)
6311         {
6312                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6313                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6314                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6315                 c[3] *= ent->alpha;
6316         }
6317         if (r_refdef.fogenabled)
6318         {
6319                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6320                 {
6321                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6322                         f2 = 1 - f1;
6323                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6324                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6325                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6326                 }
6327         }
6328 //      R_Mesh_ResetTextureState();
6329         R_SetupShader_Generic_NoTexture(false, false);
6330         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6331         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6332 }
6333
6334 void R_DrawNoModel(entity_render_t *ent)
6335 {
6336         vec3_t org;
6337         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6338         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6339                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6340         else
6341                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6342 }
6343
6344 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6345 {
6346         vec3_t right1, right2, diff, normal;
6347
6348         VectorSubtract (org2, org1, normal);
6349
6350         // calculate 'right' vector for start
6351         VectorSubtract (r_refdef.view.origin, org1, diff);
6352         CrossProduct (normal, diff, right1);
6353         VectorNormalize (right1);
6354
6355         // calculate 'right' vector for end
6356         VectorSubtract (r_refdef.view.origin, org2, diff);
6357         CrossProduct (normal, diff, right2);
6358         VectorNormalize (right2);
6359
6360         vert[ 0] = org1[0] + width * right1[0];
6361         vert[ 1] = org1[1] + width * right1[1];
6362         vert[ 2] = org1[2] + width * right1[2];
6363         vert[ 3] = org1[0] - width * right1[0];
6364         vert[ 4] = org1[1] - width * right1[1];
6365         vert[ 5] = org1[2] - width * right1[2];
6366         vert[ 6] = org2[0] - width * right2[0];
6367         vert[ 7] = org2[1] - width * right2[1];
6368         vert[ 8] = org2[2] - width * right2[2];
6369         vert[ 9] = org2[0] + width * right2[0];
6370         vert[10] = org2[1] + width * right2[1];
6371         vert[11] = org2[2] + width * right2[2];
6372 }
6373
6374 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)
6375 {
6376         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6377         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6378         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6379         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6380         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6381         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6382         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6383         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6384         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6385         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6386         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6387         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6388 }
6389
6390 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6391 {
6392         int i;
6393         float *vertex3f;
6394         float v[3];
6395         VectorSet(v, x, y, z);
6396         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6397                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6398                         break;
6399         if (i == mesh->numvertices)
6400         {
6401                 if (mesh->numvertices < mesh->maxvertices)
6402                 {
6403                         VectorCopy(v, vertex3f);
6404                         mesh->numvertices++;
6405                 }
6406                 return mesh->numvertices;
6407         }
6408         else
6409                 return i;
6410 }
6411
6412 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6413 {
6414         int i;
6415         int *e, element[3];
6416         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6417         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6418         e = mesh->element3i + mesh->numtriangles * 3;
6419         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6420         {
6421                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6422                 if (mesh->numtriangles < mesh->maxtriangles)
6423                 {
6424                         *e++ = element[0];
6425                         *e++ = element[1];
6426                         *e++ = element[2];
6427                         mesh->numtriangles++;
6428                 }
6429                 element[1] = element[2];
6430         }
6431 }
6432
6433 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6434 {
6435         int i;
6436         int *e, element[3];
6437         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6438         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6439         e = mesh->element3i + mesh->numtriangles * 3;
6440         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6441         {
6442                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6443                 if (mesh->numtriangles < mesh->maxtriangles)
6444                 {
6445                         *e++ = element[0];
6446                         *e++ = element[1];
6447                         *e++ = element[2];
6448                         mesh->numtriangles++;
6449                 }
6450                 element[1] = element[2];
6451         }
6452 }
6453
6454 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6455 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6456 {
6457         int planenum, planenum2;
6458         int w;
6459         int tempnumpoints;
6460         mplane_t *plane, *plane2;
6461         double maxdist;
6462         double temppoints[2][256*3];
6463         // figure out how large a bounding box we need to properly compute this brush
6464         maxdist = 0;
6465         for (w = 0;w < numplanes;w++)
6466                 maxdist = max(maxdist, fabs(planes[w].dist));
6467         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6468         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6469         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6470         {
6471                 w = 0;
6472                 tempnumpoints = 4;
6473                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6474                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6475                 {
6476                         if (planenum2 == planenum)
6477                                 continue;
6478                         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);
6479                         w = !w;
6480                 }
6481                 if (tempnumpoints < 3)
6482                         continue;
6483                 // generate elements forming a triangle fan for this polygon
6484                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6485         }
6486 }
6487
6488 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6489 {
6490         if(parms[0] == 0 && parms[1] == 0)
6491                 return false;
6492         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6493                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6494                         return false;
6495         return true;
6496 }
6497
6498 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6499 {
6500         double index, f;
6501         index = parms[2] + rsurface.shadertime * parms[3];
6502         index -= floor(index);
6503         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6504         {
6505         default:
6506         case Q3WAVEFUNC_NONE:
6507         case Q3WAVEFUNC_NOISE:
6508         case Q3WAVEFUNC_COUNT:
6509                 f = 0;
6510                 break;
6511         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6512         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6513         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6514         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6515         case Q3WAVEFUNC_TRIANGLE:
6516                 index *= 4;
6517                 f = index - floor(index);
6518                 if (index < 1)
6519                 {
6520                         // f = f;
6521                 }
6522                 else if (index < 2)
6523                         f = 1 - f;
6524                 else if (index < 3)
6525                         f = -f;
6526                 else
6527                         f = -(1 - f);
6528                 break;
6529         }
6530         f = parms[0] + parms[1] * f;
6531         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6532                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6533         return (float) f;
6534 }
6535
6536 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6537 {
6538         int w, h, idx;
6539         float shadertime;
6540         float f;
6541         float offsetd[2];
6542         float tcmat[12];
6543         matrix4x4_t matrix, temp;
6544         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6545         // it's better to have one huge fixup every 9 hours than gradual
6546         // degradation over time which looks consistently bad after many hours.
6547         //
6548         // tcmod scroll in particular suffers from this degradation which can't be
6549         // effectively worked around even with floor() tricks because we don't
6550         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6551         // a workaround involving floor() would be incorrect anyway...
6552         shadertime = rsurface.shadertime;
6553         if (shadertime >= 32768.0f)
6554                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6555         switch(tcmod->tcmod)
6556         {
6557                 case Q3TCMOD_COUNT:
6558                 case Q3TCMOD_NONE:
6559                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6560                                 matrix = r_waterscrollmatrix;
6561                         else
6562                                 matrix = identitymatrix;
6563                         break;
6564                 case Q3TCMOD_ENTITYTRANSLATE:
6565                         // this is used in Q3 to allow the gamecode to control texcoord
6566                         // scrolling on the entity, which is not supported in darkplaces yet.
6567                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6568                         break;
6569                 case Q3TCMOD_ROTATE:
6570                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6571                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6572                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6573                         break;
6574                 case Q3TCMOD_SCALE:
6575                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6576                         break;
6577                 case Q3TCMOD_SCROLL:
6578                         // this particular tcmod is a "bug for bug" compatible one with regards to
6579                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6580                         // specifically did the wrapping and so we must mimic that...
6581                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6582                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6583                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6584                         break;
6585                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6586                         w = (int) tcmod->parms[0];
6587                         h = (int) tcmod->parms[1];
6588                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6589                         f = f - floor(f);
6590                         idx = (int) floor(f * w * h);
6591                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6592                         break;
6593                 case Q3TCMOD_STRETCH:
6594                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6595                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6596                         break;
6597                 case Q3TCMOD_TRANSFORM:
6598                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6599                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6600                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6601                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6602                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6603                         break;
6604                 case Q3TCMOD_TURBULENT:
6605                         // this is handled in the RSurf_PrepareVertices function
6606                         matrix = identitymatrix;
6607                         break;
6608         }
6609         temp = *texmatrix;
6610         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6611 }
6612
6613 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6614 {
6615         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6616         char name[MAX_QPATH];
6617         skinframe_t *skinframe;
6618         unsigned char pixels[296*194];
6619         strlcpy(cache->name, skinname, sizeof(cache->name));
6620         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6621         if (developer_loading.integer)
6622                 Con_Printf("loading %s\n", name);
6623         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6624         if (!skinframe || !skinframe->base)
6625         {
6626                 unsigned char *f;
6627                 fs_offset_t filesize;
6628                 skinframe = NULL;
6629                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6630                 if (f)
6631                 {
6632                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6633                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6634                         Mem_Free(f);
6635                 }
6636         }
6637         cache->skinframe = skinframe;
6638 }
6639
6640 texture_t *R_GetCurrentTexture(texture_t *t)
6641 {
6642         int i, q;
6643         const entity_render_t *ent = rsurface.entity;
6644         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6645         q3shaderinfo_layer_tcmod_t *tcmod;
6646         float specularscale = 0.0f;
6647
6648         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6649                 return t->currentframe;
6650         t->update_lastrenderframe = r_textureframe;
6651         t->update_lastrenderentity = (void *)ent;
6652
6653         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6654                 t->camera_entity = ent->entitynumber;
6655         else
6656                 t->camera_entity = 0;
6657
6658         // switch to an alternate material if this is a q1bsp animated material
6659         {
6660                 texture_t *texture = t;
6661                 int s = rsurface.ent_skinnum;
6662                 if ((unsigned int)s >= (unsigned int)model->numskins)
6663                         s = 0;
6664                 if (model->skinscenes)
6665                 {
6666                         if (model->skinscenes[s].framecount > 1)
6667                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6668                         else
6669                                 s = model->skinscenes[s].firstframe;
6670                 }
6671                 if (s > 0)
6672                         t = t + s * model->num_surfaces;
6673                 if (t->animated)
6674                 {
6675                         // use an alternate animation if the entity's frame is not 0,
6676                         // and only if the texture has an alternate animation
6677                         if (t->animated == 2) // q2bsp
6678                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6679                         else if (rsurface.ent_alttextures && t->anim_total[1])
6680                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6681                         else
6682                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6683                 }
6684                 texture->currentframe = t;
6685         }
6686
6687         // update currentskinframe to be a qw skin or animation frame
6688         if (rsurface.ent_qwskin >= 0)
6689         {
6690                 i = rsurface.ent_qwskin;
6691                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6692                 {
6693                         r_qwskincache_size = cl.maxclients;
6694                         if (r_qwskincache)
6695                                 Mem_Free(r_qwskincache);
6696                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6697                 }
6698                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6699                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6700                 t->currentskinframe = r_qwskincache[i].skinframe;
6701                 if (t->materialshaderpass && t->currentskinframe == NULL)
6702                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6703         }
6704         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6705                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6706         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6707                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6708
6709         t->currentmaterialflags = t->basematerialflags;
6710         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6711         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6712                 t->currentalpha *= r_wateralpha.value;
6713         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6714                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6715         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6716                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6717
6718         // decide on which type of lighting to use for this surface
6719         if (rsurface.entity->render_modellight_forced)
6720                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6721         if (rsurface.entity->render_rtlight_disabled)
6722                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6723         if (rsurface.entity->render_lightgrid)
6724                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6725         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6726         {
6727                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6728                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6729                 for (q = 0; q < 3; q++)
6730                 {
6731                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6732                         t->render_modellight_lightdir[q] = q == 2;
6733                         t->render_modellight_ambient[q] = 1;
6734                         t->render_modellight_diffuse[q] = 0;
6735                         t->render_modellight_specular[q] = 0;
6736                         t->render_lightmap_ambient[q] = 0;
6737                         t->render_lightmap_diffuse[q] = 0;
6738                         t->render_lightmap_specular[q] = 0;
6739                         t->render_rtlight_diffuse[q] = 0;
6740                         t->render_rtlight_specular[q] = 0;
6741                 }
6742         }
6743         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6744         {
6745                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6746                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6747                 for (q = 0; q < 3; q++)
6748                 {
6749                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6750                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6751                         t->render_modellight_lightdir[q] = q == 2;
6752                         t->render_modellight_diffuse[q] = 0;
6753                         t->render_modellight_specular[q] = 0;
6754                         t->render_lightmap_ambient[q] = 0;
6755                         t->render_lightmap_diffuse[q] = 0;
6756                         t->render_lightmap_specular[q] = 0;
6757                         t->render_rtlight_diffuse[q] = 0;
6758                         t->render_rtlight_specular[q] = 0;
6759                 }
6760         }
6761         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6762         {
6763                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6764                 for (q = 0; q < 3; q++)
6765                 {
6766                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6767                         t->render_modellight_lightdir[q] = q == 2;
6768                         t->render_modellight_ambient[q] = 0;
6769                         t->render_modellight_diffuse[q] = 0;
6770                         t->render_modellight_specular[q] = 0;
6771                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6772                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6773                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6774                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6775                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6776                 }
6777         }
6778         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6779         {
6780                 // ambient + single direction light (modellight)
6781                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6782                 for (q = 0; q < 3; q++)
6783                 {
6784                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6785                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6786                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6787                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6788                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6789                         t->render_lightmap_ambient[q] = 0;
6790                         t->render_lightmap_diffuse[q] = 0;
6791                         t->render_lightmap_specular[q] = 0;
6792                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6793                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6794                 }
6795         }
6796         else
6797         {
6798                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6799                 for (q = 0; q < 3; q++)
6800                 {
6801                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6802                         t->render_modellight_lightdir[q] = q == 2;
6803                         t->render_modellight_ambient[q] = 0;
6804                         t->render_modellight_diffuse[q] = 0;
6805                         t->render_modellight_specular[q] = 0;
6806                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6807                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6808                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6809                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6810                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6811                 }
6812         }
6813
6814         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6815         {
6816                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6817                 // attribute, we punt it to the lightmap path and hope for the best,
6818                 // but lighting doesn't work.
6819                 //
6820                 // FIXME: this is fine for effects but CSQC polygons should be subject
6821                 // to lighting.
6822                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6823                 for (q = 0; q < 3; q++)
6824                 {
6825                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6826                         t->render_modellight_lightdir[q] = q == 2;
6827                         t->render_modellight_ambient[q] = 0;
6828                         t->render_modellight_diffuse[q] = 0;
6829                         t->render_modellight_specular[q] = 0;
6830                         t->render_lightmap_ambient[q] = 0;
6831                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6832                         t->render_lightmap_specular[q] = 0;
6833                         t->render_rtlight_diffuse[q] = 0;
6834                         t->render_rtlight_specular[q] = 0;
6835                 }
6836         }
6837
6838         for (q = 0; q < 3; q++)
6839         {
6840                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6841                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6842         }
6843
6844         if (rsurface.ent_flags & RENDER_ADDITIVE)
6845                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6846         else if (t->currentalpha < 1)
6847                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6848         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6849         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6850                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6851         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6852                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6853         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6854                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6855         if (t->backgroundshaderpass)
6856                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6857         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6858         {
6859                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6860                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6861         }
6862         else
6863                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6864         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6865         {
6866                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6867                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6868         }
6869         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6870                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6871
6872         // there is no tcmod
6873         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6874         {
6875                 t->currenttexmatrix = r_waterscrollmatrix;
6876                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6877         }
6878         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6879         {
6880                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6881                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6882         }
6883
6884         if (t->materialshaderpass)
6885                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6886                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6887
6888         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6889         if (t->currentskinframe->qpixels)
6890                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6891         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6892         if (!t->basetexture)
6893                 t->basetexture = r_texture_notexture;
6894         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6895         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6896         t->nmaptexture = t->currentskinframe->nmap;
6897         if (!t->nmaptexture)
6898                 t->nmaptexture = r_texture_blanknormalmap;
6899         t->glosstexture = r_texture_black;
6900         t->glowtexture = t->currentskinframe->glow;
6901         t->fogtexture = t->currentskinframe->fog;
6902         t->reflectmasktexture = t->currentskinframe->reflect;
6903         if (t->backgroundshaderpass)
6904         {
6905                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6906                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6907                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6908                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6909                 t->backgroundglosstexture = r_texture_black;
6910                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6911                 if (!t->backgroundnmaptexture)
6912                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6913                 // make sure that if glow is going to be used, both textures are not NULL
6914                 if (!t->backgroundglowtexture && t->glowtexture)
6915                         t->backgroundglowtexture = r_texture_black;
6916                 if (!t->glowtexture && t->backgroundglowtexture)
6917                         t->glowtexture = r_texture_black;
6918         }
6919         else
6920         {
6921                 t->backgroundbasetexture = r_texture_white;
6922                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6923                 t->backgroundglosstexture = r_texture_black;
6924                 t->backgroundglowtexture = NULL;
6925         }
6926         t->specularpower = r_shadow_glossexponent.value;
6927         // TODO: store reference values for these in the texture?
6928         if (r_shadow_gloss.integer > 0)
6929         {
6930                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6931                 {
6932                         if (r_shadow_glossintensity.value > 0)
6933                         {
6934                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6935                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6936                                 specularscale = r_shadow_glossintensity.value;
6937                         }
6938                 }
6939                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6940                 {
6941                         t->glosstexture = r_texture_white;
6942                         t->backgroundglosstexture = r_texture_white;
6943                         specularscale = r_shadow_gloss2intensity.value;
6944                         t->specularpower = r_shadow_gloss2exponent.value;
6945                 }
6946         }
6947         specularscale *= t->specularscalemod;
6948         t->specularpower *= t->specularpowermod;
6949
6950         // lightmaps mode looks bad with dlights using actual texturing, so turn
6951         // off the colormap and glossmap, but leave the normalmap on as it still
6952         // accurately represents the shading involved
6953         if (gl_lightmaps.integer)
6954         {
6955                 t->basetexture = r_texture_grey128;
6956                 t->pantstexture = r_texture_black;
6957                 t->shirttexture = r_texture_black;
6958                 if (gl_lightmaps.integer < 2)
6959                         t->nmaptexture = r_texture_blanknormalmap;
6960                 t->glosstexture = r_texture_black;
6961                 t->glowtexture = NULL;
6962                 t->fogtexture = NULL;
6963                 t->reflectmasktexture = NULL;
6964                 t->backgroundbasetexture = NULL;
6965                 if (gl_lightmaps.integer < 2)
6966                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6967                 t->backgroundglosstexture = r_texture_black;
6968                 t->backgroundglowtexture = NULL;
6969                 specularscale = 0;
6970                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6971         }
6972
6973         if (specularscale != 1.0f)
6974         {
6975                 for (q = 0; q < 3; q++)
6976                 {
6977                         t->render_modellight_specular[q] *= specularscale;
6978                         t->render_lightmap_specular[q] *= specularscale;
6979                         t->render_rtlight_specular[q] *= specularscale;
6980                 }
6981         }
6982
6983         t->currentblendfunc[0] = GL_ONE;
6984         t->currentblendfunc[1] = GL_ZERO;
6985         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6986         {
6987                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6988                 t->currentblendfunc[1] = GL_ONE;
6989         }
6990         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6991         {
6992                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6993                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6994         }
6995         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6996         {
6997                 t->currentblendfunc[0] = t->customblendfunc[0];
6998                 t->currentblendfunc[1] = t->customblendfunc[1];
6999         }
7000
7001         return t;
7002 }
7003
7004 rsurfacestate_t rsurface;
7005
7006 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7007 {
7008         dp_model_t *model = ent->model;
7009         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7010         //      return;
7011         rsurface.entity = (entity_render_t *)ent;
7012         rsurface.skeleton = ent->skeleton;
7013         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7014         rsurface.ent_skinnum = ent->skinnum;
7015         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;
7016         rsurface.ent_flags = ent->flags;
7017         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7018                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7019         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7020         rsurface.matrix = ent->matrix;
7021         rsurface.inversematrix = ent->inversematrix;
7022         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7023         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7024         R_EntityMatrix(&rsurface.matrix);
7025         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7026         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7027         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7028         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7029         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7030         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7031         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7032         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7033         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7034         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7035         if (ent->model->brush.submodel && !prepass)
7036         {
7037                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7038                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7039         }
7040         // if the animcache code decided it should use the shader path, skip the deform step
7041         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7042         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7043         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7044         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7045         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7046         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7047         {
7048                 if (ent->animcache_vertex3f)
7049                 {
7050                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7051                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7052                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7053                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7054                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7055                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7056                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7057                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7058                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7059                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7060                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7061                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7062                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7063                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7064                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7065                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7066                 }
7067                 else if (wanttangents)
7068                 {
7069                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7070                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7071                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7072                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7073                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7074                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7075                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7076                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7077                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7078                         rsurface.modelvertex3f_vertexbuffer = NULL;
7079                         rsurface.modelvertex3f_bufferoffset = 0;
7080                         rsurface.modelvertex3f_vertexbuffer = 0;
7081                         rsurface.modelvertex3f_bufferoffset = 0;
7082                         rsurface.modelsvector3f_vertexbuffer = 0;
7083                         rsurface.modelsvector3f_bufferoffset = 0;
7084                         rsurface.modeltvector3f_vertexbuffer = 0;
7085                         rsurface.modeltvector3f_bufferoffset = 0;
7086                         rsurface.modelnormal3f_vertexbuffer = 0;
7087                         rsurface.modelnormal3f_bufferoffset = 0;
7088                 }
7089                 else if (wantnormals)
7090                 {
7091                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7092                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7093                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7094                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7095                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7096                         rsurface.modelsvector3f = NULL;
7097                         rsurface.modeltvector3f = NULL;
7098                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7099                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7100                         rsurface.modelvertex3f_vertexbuffer = NULL;
7101                         rsurface.modelvertex3f_bufferoffset = 0;
7102                         rsurface.modelvertex3f_vertexbuffer = 0;
7103                         rsurface.modelvertex3f_bufferoffset = 0;
7104                         rsurface.modelsvector3f_vertexbuffer = 0;
7105                         rsurface.modelsvector3f_bufferoffset = 0;
7106                         rsurface.modeltvector3f_vertexbuffer = 0;
7107                         rsurface.modeltvector3f_bufferoffset = 0;
7108                         rsurface.modelnormal3f_vertexbuffer = 0;
7109                         rsurface.modelnormal3f_bufferoffset = 0;
7110                 }
7111                 else
7112                 {
7113                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7114                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7115                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7116                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7117                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7118                         rsurface.modelsvector3f = NULL;
7119                         rsurface.modeltvector3f = NULL;
7120                         rsurface.modelnormal3f = NULL;
7121                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7122                         rsurface.modelvertex3f_vertexbuffer = NULL;
7123                         rsurface.modelvertex3f_bufferoffset = 0;
7124                         rsurface.modelvertex3f_vertexbuffer = 0;
7125                         rsurface.modelvertex3f_bufferoffset = 0;
7126                         rsurface.modelsvector3f_vertexbuffer = 0;
7127                         rsurface.modelsvector3f_bufferoffset = 0;
7128                         rsurface.modeltvector3f_vertexbuffer = 0;
7129                         rsurface.modeltvector3f_bufferoffset = 0;
7130                         rsurface.modelnormal3f_vertexbuffer = 0;
7131                         rsurface.modelnormal3f_bufferoffset = 0;
7132                 }
7133                 rsurface.modelgeneratedvertex = true;
7134         }
7135         else
7136         {
7137                 if (rsurface.entityskeletaltransform3x4)
7138                 {
7139                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7140                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7141                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7142                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7143                 }
7144                 else
7145                 {
7146                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7147                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7148                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7149                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7150                 }
7151                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7152                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7153                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7154                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7155                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7156                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7157                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7158                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7159                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7160                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7161                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7162                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7163                 rsurface.modelgeneratedvertex = false;
7164         }
7165         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7166         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7167         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7168         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7169         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7170         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7171         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7172         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7173         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7174         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7175         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7176         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7177         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7178         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7179         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7180         rsurface.modelelement3i = model->surfmesh.data_element3i;
7181         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7182         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7183         rsurface.modelelement3s = model->surfmesh.data_element3s;
7184         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7185         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7186         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7187         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7188         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7189         rsurface.modelsurfaces = model->data_surfaces;
7190         rsurface.batchgeneratedvertex = false;
7191         rsurface.batchfirstvertex = 0;
7192         rsurface.batchnumvertices = 0;
7193         rsurface.batchfirsttriangle = 0;
7194         rsurface.batchnumtriangles = 0;
7195         rsurface.batchvertex3f  = NULL;
7196         rsurface.batchvertex3f_vertexbuffer = NULL;
7197         rsurface.batchvertex3f_bufferoffset = 0;
7198         rsurface.batchsvector3f = NULL;
7199         rsurface.batchsvector3f_vertexbuffer = NULL;
7200         rsurface.batchsvector3f_bufferoffset = 0;
7201         rsurface.batchtvector3f = NULL;
7202         rsurface.batchtvector3f_vertexbuffer = NULL;
7203         rsurface.batchtvector3f_bufferoffset = 0;
7204         rsurface.batchnormal3f  = NULL;
7205         rsurface.batchnormal3f_vertexbuffer = NULL;
7206         rsurface.batchnormal3f_bufferoffset = 0;
7207         rsurface.batchlightmapcolor4f = NULL;
7208         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7209         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7210         rsurface.batchtexcoordtexture2f = NULL;
7211         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7212         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7213         rsurface.batchtexcoordlightmap2f = NULL;
7214         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7215         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7216         rsurface.batchskeletalindex4ub = NULL;
7217         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7218         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7219         rsurface.batchskeletalweight4ub = NULL;
7220         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7221         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7222         rsurface.batchelement3i = NULL;
7223         rsurface.batchelement3i_indexbuffer = NULL;
7224         rsurface.batchelement3i_bufferoffset = 0;
7225         rsurface.batchelement3s = NULL;
7226         rsurface.batchelement3s_indexbuffer = NULL;
7227         rsurface.batchelement3s_bufferoffset = 0;
7228         rsurface.forcecurrenttextureupdate = false;
7229 }
7230
7231 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
7232 {
7233         rsurface.entity = r_refdef.scene.worldentity;
7234         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7235                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7236                 // A better approach could be making this copy only once per frame.
7237                 static entity_render_t custom_entity;
7238                 int q;
7239                 custom_entity = *rsurface.entity;
7240                 for (q = 0; q < 3; ++q) {
7241                         float colormod = q == 0 ? r : q == 1 ? g : b;
7242                         custom_entity.render_fullbright[q] *= colormod;
7243                         custom_entity.render_modellight_ambient[q] *= colormod;
7244                         custom_entity.render_modellight_diffuse[q] *= colormod;
7245                         custom_entity.render_lightmap_ambient[q] *= colormod;
7246                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7247                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7248                 }
7249                 custom_entity.alpha *= a;
7250                 rsurface.entity = &custom_entity;
7251         }
7252         rsurface.skeleton = NULL;
7253         rsurface.ent_skinnum = 0;
7254         rsurface.ent_qwskin = -1;
7255         rsurface.ent_flags = entflags;
7256         rsurface.shadertime = r_refdef.scene.time - shadertime;
7257         rsurface.modelnumvertices = numvertices;
7258         rsurface.modelnumtriangles = numtriangles;
7259         rsurface.matrix = *matrix;
7260         rsurface.inversematrix = *inversematrix;
7261         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7262         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7263         R_EntityMatrix(&rsurface.matrix);
7264         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7265         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7266         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7267         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7268         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7269         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7270         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7271         rsurface.frameblend[0].lerp = 1;
7272         rsurface.ent_alttextures = false;
7273         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7274         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7275         rsurface.entityskeletaltransform3x4 = NULL;
7276         rsurface.entityskeletaltransform3x4buffer = NULL;
7277         rsurface.entityskeletaltransform3x4offset = 0;
7278         rsurface.entityskeletaltransform3x4size = 0;
7279         rsurface.entityskeletalnumtransforms = 0;
7280         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7281         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7282         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7283         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7284         if (wanttangents)
7285         {
7286                 rsurface.modelvertex3f = (float *)vertex3f;
7287                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7288                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7289                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7290         }
7291         else if (wantnormals)
7292         {
7293                 rsurface.modelvertex3f = (float *)vertex3f;
7294                 rsurface.modelsvector3f = NULL;
7295                 rsurface.modeltvector3f = NULL;
7296                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7297         }
7298         else
7299         {
7300                 rsurface.modelvertex3f = (float *)vertex3f;
7301                 rsurface.modelsvector3f = NULL;
7302                 rsurface.modeltvector3f = NULL;
7303                 rsurface.modelnormal3f = NULL;
7304         }
7305         rsurface.modelvertex3f_vertexbuffer = 0;
7306         rsurface.modelvertex3f_bufferoffset = 0;
7307         rsurface.modelsvector3f_vertexbuffer = 0;
7308         rsurface.modelsvector3f_bufferoffset = 0;
7309         rsurface.modeltvector3f_vertexbuffer = 0;
7310         rsurface.modeltvector3f_bufferoffset = 0;
7311         rsurface.modelnormal3f_vertexbuffer = 0;
7312         rsurface.modelnormal3f_bufferoffset = 0;
7313         rsurface.modelgeneratedvertex = true;
7314         rsurface.modellightmapcolor4f  = (float *)color4f;
7315         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7316         rsurface.modellightmapcolor4f_bufferoffset = 0;
7317         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7318         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7319         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7320         rsurface.modeltexcoordlightmap2f  = NULL;
7321         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7322         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7323         rsurface.modelskeletalindex4ub = NULL;
7324         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7325         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7326         rsurface.modelskeletalweight4ub = NULL;
7327         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7328         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7329         rsurface.modelelement3i = (int *)element3i;
7330         rsurface.modelelement3i_indexbuffer = NULL;
7331         rsurface.modelelement3i_bufferoffset = 0;
7332         rsurface.modelelement3s = (unsigned short *)element3s;
7333         rsurface.modelelement3s_indexbuffer = NULL;
7334         rsurface.modelelement3s_bufferoffset = 0;
7335         rsurface.modellightmapoffsets = NULL;
7336         rsurface.modelsurfaces = NULL;
7337         rsurface.batchgeneratedvertex = false;
7338         rsurface.batchfirstvertex = 0;
7339         rsurface.batchnumvertices = 0;
7340         rsurface.batchfirsttriangle = 0;
7341         rsurface.batchnumtriangles = 0;
7342         rsurface.batchvertex3f  = NULL;
7343         rsurface.batchvertex3f_vertexbuffer = NULL;
7344         rsurface.batchvertex3f_bufferoffset = 0;
7345         rsurface.batchsvector3f = NULL;
7346         rsurface.batchsvector3f_vertexbuffer = NULL;
7347         rsurface.batchsvector3f_bufferoffset = 0;
7348         rsurface.batchtvector3f = NULL;
7349         rsurface.batchtvector3f_vertexbuffer = NULL;
7350         rsurface.batchtvector3f_bufferoffset = 0;
7351         rsurface.batchnormal3f  = NULL;
7352         rsurface.batchnormal3f_vertexbuffer = NULL;
7353         rsurface.batchnormal3f_bufferoffset = 0;
7354         rsurface.batchlightmapcolor4f = NULL;
7355         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7356         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7357         rsurface.batchtexcoordtexture2f = NULL;
7358         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7359         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7360         rsurface.batchtexcoordlightmap2f = NULL;
7361         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7362         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7363         rsurface.batchskeletalindex4ub = NULL;
7364         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7365         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7366         rsurface.batchskeletalweight4ub = NULL;
7367         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7368         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7369         rsurface.batchelement3i = NULL;
7370         rsurface.batchelement3i_indexbuffer = NULL;
7371         rsurface.batchelement3i_bufferoffset = 0;
7372         rsurface.batchelement3s = NULL;
7373         rsurface.batchelement3s_indexbuffer = NULL;
7374         rsurface.batchelement3s_bufferoffset = 0;
7375         rsurface.forcecurrenttextureupdate = true;
7376
7377         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7378         {
7379                 if ((wantnormals || wanttangents) && !normal3f)
7380                 {
7381                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7382                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7383                 }
7384                 if (wanttangents && !svector3f)
7385                 {
7386                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7387                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7388                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7389                 }
7390         }
7391 }
7392
7393 float RSurf_FogPoint(const float *v)
7394 {
7395         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7396         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7397         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7398         float FogHeightFade = r_refdef.fogheightfade;
7399         float fogfrac;
7400         unsigned int fogmasktableindex;
7401         if (r_refdef.fogplaneviewabove)
7402                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7403         else
7404                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7405         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7406         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7407 }
7408
7409 float RSurf_FogVertex(const float *v)
7410 {
7411         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7412         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7413         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7414         float FogHeightFade = rsurface.fogheightfade;
7415         float fogfrac;
7416         unsigned int fogmasktableindex;
7417         if (r_refdef.fogplaneviewabove)
7418                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7419         else
7420                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7421         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7422         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7423 }
7424
7425 void RSurf_UploadBuffersForBatch(void)
7426 {
7427         // 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)
7428         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7429         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7430                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7431         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7432                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7433         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7434                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7435         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7436                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7437         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7438                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7439         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7440                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7441         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7442                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7443         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7444                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7445         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7446                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7447
7448         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7449                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7450         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7451                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7452
7453         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7454         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7455         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7456         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7457         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7458         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7459         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7460         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7461         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7462         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7463 }
7464
7465 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7466 {
7467         int i;
7468         for (i = 0;i < numelements;i++)
7469                 outelement3i[i] = inelement3i[i] + adjust;
7470 }
7471
7472 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7473 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7474 {
7475         int deformindex;
7476         int firsttriangle;
7477         int numtriangles;
7478         int firstvertex;
7479         int endvertex;
7480         int numvertices;
7481         int surfacefirsttriangle;
7482         int surfacenumtriangles;
7483         int surfacefirstvertex;
7484         int surfaceendvertex;
7485         int surfacenumvertices;
7486         int batchnumsurfaces = texturenumsurfaces;
7487         int batchnumvertices;
7488         int batchnumtriangles;
7489         int i, j;
7490         qboolean gaps;
7491         qboolean dynamicvertex;
7492         float amplitude;
7493         float animpos;
7494         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7495         float waveparms[4];
7496         unsigned char *ub;
7497         q3shaderinfo_deform_t *deform;
7498         const msurface_t *surface, *firstsurface;
7499         if (!texturenumsurfaces)
7500                 return;
7501         // find vertex range of this surface batch
7502         gaps = false;
7503         firstsurface = texturesurfacelist[0];
7504         firsttriangle = firstsurface->num_firsttriangle;
7505         batchnumvertices = 0;
7506         batchnumtriangles = 0;
7507         firstvertex = endvertex = firstsurface->num_firstvertex;
7508         for (i = 0;i < texturenumsurfaces;i++)
7509         {
7510                 surface = texturesurfacelist[i];
7511                 if (surface != firstsurface + i)
7512                         gaps = true;
7513                 surfacefirstvertex = surface->num_firstvertex;
7514                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7515                 surfacenumvertices = surface->num_vertices;
7516                 surfacenumtriangles = surface->num_triangles;
7517                 if (firstvertex > surfacefirstvertex)
7518                         firstvertex = surfacefirstvertex;
7519                 if (endvertex < surfaceendvertex)
7520                         endvertex = surfaceendvertex;
7521                 batchnumvertices += surfacenumvertices;
7522                 batchnumtriangles += surfacenumtriangles;
7523         }
7524
7525         r_refdef.stats[r_stat_batch_batches]++;
7526         if (gaps)
7527                 r_refdef.stats[r_stat_batch_withgaps]++;
7528         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7529         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7530         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7531
7532         // we now know the vertex range used, and if there are any gaps in it
7533         rsurface.batchfirstvertex = firstvertex;
7534         rsurface.batchnumvertices = endvertex - firstvertex;
7535         rsurface.batchfirsttriangle = firsttriangle;
7536         rsurface.batchnumtriangles = batchnumtriangles;
7537
7538         // check if any dynamic vertex processing must occur
7539         dynamicvertex = false;
7540
7541         // we must use vertexbuffers for rendering, we can upload vertex buffers
7542         // easily enough but if the basevertex is non-zero it becomes more
7543         // difficult, so force dynamicvertex path in that case - it's suboptimal
7544         // but the most optimal case is to have the geometry sources provide their
7545         // own anyway.
7546         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7547                 dynamicvertex = true;
7548
7549         // a cvar to force the dynamic vertex path to be taken, for debugging
7550         if (r_batch_debugdynamicvertexpath.integer)
7551         {
7552                 if (!dynamicvertex)
7553                 {
7554                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7555                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7556                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7557                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7558                 }
7559                 dynamicvertex = true;
7560         }
7561
7562         // if there is a chance of animated vertex colors, it's a dynamic batch
7563         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7564         {
7565                 if (!dynamicvertex)
7566                 {
7567                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7568                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7569                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7570                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7571                 }
7572                 dynamicvertex = true;
7573         }
7574
7575         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7576         {
7577                 switch (deform->deform)
7578                 {
7579                 default:
7580                 case Q3DEFORM_PROJECTIONSHADOW:
7581                 case Q3DEFORM_TEXT0:
7582                 case Q3DEFORM_TEXT1:
7583                 case Q3DEFORM_TEXT2:
7584                 case Q3DEFORM_TEXT3:
7585                 case Q3DEFORM_TEXT4:
7586                 case Q3DEFORM_TEXT5:
7587                 case Q3DEFORM_TEXT6:
7588                 case Q3DEFORM_TEXT7:
7589                 case Q3DEFORM_NONE:
7590                         break;
7591                 case Q3DEFORM_AUTOSPRITE:
7592                         if (!dynamicvertex)
7593                         {
7594                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7595                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7596                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7597                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7598                         }
7599                         dynamicvertex = true;
7600                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7601                         break;
7602                 case Q3DEFORM_AUTOSPRITE2:
7603                         if (!dynamicvertex)
7604                         {
7605                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7606                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7607                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7608                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7609                         }
7610                         dynamicvertex = true;
7611                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7612                         break;
7613                 case Q3DEFORM_NORMAL:
7614                         if (!dynamicvertex)
7615                         {
7616                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7617                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7618                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7619                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7620                         }
7621                         dynamicvertex = true;
7622                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7623                         break;
7624                 case Q3DEFORM_WAVE:
7625                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7626                                 break; // if wavefunc is a nop, ignore this transform
7627                         if (!dynamicvertex)
7628                         {
7629                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7630                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7631                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7632                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7633                         }
7634                         dynamicvertex = true;
7635                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7636                         break;
7637                 case Q3DEFORM_BULGE:
7638                         if (!dynamicvertex)
7639                         {
7640                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7641                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7642                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7643                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7644                         }
7645                         dynamicvertex = true;
7646                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7647                         break;
7648                 case Q3DEFORM_MOVE:
7649                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7650                                 break; // if wavefunc is a nop, ignore this transform
7651                         if (!dynamicvertex)
7652                         {
7653                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7654                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7655                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7656                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7657                         }
7658                         dynamicvertex = true;
7659                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7660                         break;
7661                 }
7662         }
7663         if (rsurface.texture->materialshaderpass)
7664         {
7665                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7666                 {
7667                 default:
7668                 case Q3TCGEN_TEXTURE:
7669                         break;
7670                 case Q3TCGEN_LIGHTMAP:
7671                         if (!dynamicvertex)
7672                         {
7673                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7674                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7675                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7676                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7677                         }
7678                         dynamicvertex = true;
7679                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7680                         break;
7681                 case Q3TCGEN_VECTOR:
7682                         if (!dynamicvertex)
7683                         {
7684                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7685                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7686                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7687                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7688                         }
7689                         dynamicvertex = true;
7690                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7691                         break;
7692                 case Q3TCGEN_ENVIRONMENT:
7693                         if (!dynamicvertex)
7694                         {
7695                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7696                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7697                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7698                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7699                         }
7700                         dynamicvertex = true;
7701                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7702                         break;
7703                 }
7704                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7705                 {
7706                         if (!dynamicvertex)
7707                         {
7708                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7709                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7710                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7711                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7712                         }
7713                         dynamicvertex = true;
7714                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7715                 }
7716         }
7717
7718         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7719         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7720         // we ensure this by treating the vertex batch as dynamic...
7721         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7722         {
7723                 if (!dynamicvertex)
7724                 {
7725                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7726                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7727                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7728                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7729                 }
7730                 dynamicvertex = true;
7731         }
7732
7733         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7734         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7735                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7736
7737         rsurface.batchvertex3f = rsurface.modelvertex3f;
7738         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7739         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7740         rsurface.batchsvector3f = rsurface.modelsvector3f;
7741         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7742         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7743         rsurface.batchtvector3f = rsurface.modeltvector3f;
7744         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7745         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7746         rsurface.batchnormal3f = rsurface.modelnormal3f;
7747         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7748         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7749         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7750         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7751         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7752         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7753         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7754         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7755         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7756         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7757         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7758         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7759         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7760         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7761         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7762         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7763         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7764         rsurface.batchelement3i = rsurface.modelelement3i;
7765         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7766         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7767         rsurface.batchelement3s = rsurface.modelelement3s;
7768         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7769         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7770         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7771         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7772         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7773         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7774         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7775
7776         // if any dynamic vertex processing has to occur in software, we copy the
7777         // entire surface list together before processing to rebase the vertices
7778         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7779         //
7780         // if any gaps exist and we do not have a static vertex buffer, we have to
7781         // copy the surface list together to avoid wasting upload bandwidth on the
7782         // vertices in the gaps.
7783         //
7784         // if gaps exist and we have a static vertex buffer, we can choose whether
7785         // to combine the index buffer ranges into one dynamic index buffer or
7786         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7787         //
7788         // in many cases the batch is reduced to one draw call.
7789
7790         rsurface.batchmultidraw = false;
7791         rsurface.batchmultidrawnumsurfaces = 0;
7792         rsurface.batchmultidrawsurfacelist = NULL;
7793
7794         if (!dynamicvertex)
7795         {
7796                 // static vertex data, just set pointers...
7797                 rsurface.batchgeneratedvertex = false;
7798                 // if there are gaps, we want to build a combined index buffer,
7799                 // otherwise use the original static buffer with an appropriate offset
7800                 if (gaps)
7801                 {
7802                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7803                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7804                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7805                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7806                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7807                         {
7808                                 rsurface.batchmultidraw = true;
7809                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7810                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7811                                 return;
7812                         }
7813                         // build a new triangle elements array for this batch
7814                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7815                         rsurface.batchfirsttriangle = 0;
7816                         numtriangles = 0;
7817                         for (i = 0;i < texturenumsurfaces;i++)
7818                         {
7819                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7820                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7821                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7822                                 numtriangles += surfacenumtriangles;
7823                         }
7824                         rsurface.batchelement3i_indexbuffer = NULL;
7825                         rsurface.batchelement3i_bufferoffset = 0;
7826                         rsurface.batchelement3s = NULL;
7827                         rsurface.batchelement3s_indexbuffer = NULL;
7828                         rsurface.batchelement3s_bufferoffset = 0;
7829                         if (endvertex <= 65536)
7830                         {
7831                                 // make a 16bit (unsigned short) index array if possible
7832                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7833                                 for (i = 0;i < numtriangles*3;i++)
7834                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7835                         }
7836                 }
7837                 else
7838                 {
7839                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7840                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7841                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7842                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7843                 }
7844                 return;
7845         }
7846
7847         // something needs software processing, do it for real...
7848         // we only directly handle separate array data in this case and then
7849         // generate interleaved data if needed...
7850         rsurface.batchgeneratedvertex = true;
7851         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7852         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7853         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7854         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7855
7856         // now copy the vertex data into a combined array and make an index array
7857         // (this is what Quake3 does all the time)
7858         // we also apply any skeletal animation here that would have been done in
7859         // the vertex shader, because most of the dynamic vertex animation cases
7860         // need actual vertex positions and normals
7861         //if (dynamicvertex)
7862         {
7863                 rsurface.batchvertex3f = NULL;
7864                 rsurface.batchvertex3f_vertexbuffer = NULL;
7865                 rsurface.batchvertex3f_bufferoffset = 0;
7866                 rsurface.batchsvector3f = NULL;
7867                 rsurface.batchsvector3f_vertexbuffer = NULL;
7868                 rsurface.batchsvector3f_bufferoffset = 0;
7869                 rsurface.batchtvector3f = NULL;
7870                 rsurface.batchtvector3f_vertexbuffer = NULL;
7871                 rsurface.batchtvector3f_bufferoffset = 0;
7872                 rsurface.batchnormal3f = NULL;
7873                 rsurface.batchnormal3f_vertexbuffer = NULL;
7874                 rsurface.batchnormal3f_bufferoffset = 0;
7875                 rsurface.batchlightmapcolor4f = NULL;
7876                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7877                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7878                 rsurface.batchtexcoordtexture2f = NULL;
7879                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7880                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7881                 rsurface.batchtexcoordlightmap2f = NULL;
7882                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7883                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7884                 rsurface.batchskeletalindex4ub = NULL;
7885                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7886                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7887                 rsurface.batchskeletalweight4ub = NULL;
7888                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7889                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7890                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7891                 rsurface.batchelement3i_indexbuffer = NULL;
7892                 rsurface.batchelement3i_bufferoffset = 0;
7893                 rsurface.batchelement3s = NULL;
7894                 rsurface.batchelement3s_indexbuffer = NULL;
7895                 rsurface.batchelement3s_bufferoffset = 0;
7896                 rsurface.batchskeletaltransform3x4buffer = NULL;
7897                 rsurface.batchskeletaltransform3x4offset = 0;
7898                 rsurface.batchskeletaltransform3x4size = 0;
7899                 // we'll only be setting up certain arrays as needed
7900                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7901                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7902                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7903                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7904                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7905                 {
7906                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7907                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7908                 }
7909                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7910                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7911                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7912                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7913                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7914                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7915                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7916                 {
7917                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7918                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7919                 }
7920                 numvertices = 0;
7921                 numtriangles = 0;
7922                 for (i = 0;i < texturenumsurfaces;i++)
7923                 {
7924                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7925                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7926                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7927                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7928                         // copy only the data requested
7929                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7930                         {
7931                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7932                                 {
7933                                         if (rsurface.batchvertex3f)
7934                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7935                                         else
7936                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7937                                 }
7938                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7939                                 {
7940                                         if (rsurface.modelnormal3f)
7941                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7942                                         else
7943                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7944                                 }
7945                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7946                                 {
7947                                         if (rsurface.modelsvector3f)
7948                                         {
7949                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7950                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7951                                         }
7952                                         else
7953                                         {
7954                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7955                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7956                                         }
7957                                 }
7958                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7959                                 {
7960                                         if (rsurface.modellightmapcolor4f)
7961                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7962                                         else
7963                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7964                                 }
7965                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7966                                 {
7967                                         if (rsurface.modeltexcoordtexture2f)
7968                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7969                                         else
7970                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7971                                 }
7972                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7973                                 {
7974                                         if (rsurface.modeltexcoordlightmap2f)
7975                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7976                                         else
7977                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7978                                 }
7979                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7980                                 {
7981                                         if (rsurface.modelskeletalindex4ub)
7982                                         {
7983                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7984                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7985                                         }
7986                                         else
7987                                         {
7988                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7989                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7990                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7991                                                 for (j = 0;j < surfacenumvertices;j++)
7992                                                         ub[j*4] = 255;
7993                                         }
7994                                 }
7995                         }
7996                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7997                         numvertices += surfacenumvertices;
7998                         numtriangles += surfacenumtriangles;
7999                 }
8000
8001                 // generate a 16bit index array as well if possible
8002                 // (in general, dynamic batches fit)
8003                 if (numvertices <= 65536)
8004                 {
8005                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8006                         for (i = 0;i < numtriangles*3;i++)
8007                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8008                 }
8009
8010                 // since we've copied everything, the batch now starts at 0
8011                 rsurface.batchfirstvertex = 0;
8012                 rsurface.batchnumvertices = batchnumvertices;
8013                 rsurface.batchfirsttriangle = 0;
8014                 rsurface.batchnumtriangles = batchnumtriangles;
8015         }
8016
8017         // apply skeletal animation that would have been done in the vertex shader
8018         if (rsurface.batchskeletaltransform3x4)
8019         {
8020                 const unsigned char *si;
8021                 const unsigned char *sw;
8022                 const float *t[4];
8023                 const float *b = rsurface.batchskeletaltransform3x4;
8024                 float *vp, *vs, *vt, *vn;
8025                 float w[4];
8026                 float m[3][4], n[3][4];
8027                 float tp[3], ts[3], tt[3], tn[3];
8028                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8029                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8030                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8031                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8032                 si = rsurface.batchskeletalindex4ub;
8033                 sw = rsurface.batchskeletalweight4ub;
8034                 vp = rsurface.batchvertex3f;
8035                 vs = rsurface.batchsvector3f;
8036                 vt = rsurface.batchtvector3f;
8037                 vn = rsurface.batchnormal3f;
8038                 memset(m[0], 0, sizeof(m));
8039                 memset(n[0], 0, sizeof(n));
8040                 for (i = 0;i < batchnumvertices;i++)
8041                 {
8042                         t[0] = b + si[0]*12;
8043                         if (sw[0] == 255)
8044                         {
8045                                 // common case - only one matrix
8046                                 m[0][0] = t[0][ 0];
8047                                 m[0][1] = t[0][ 1];
8048                                 m[0][2] = t[0][ 2];
8049                                 m[0][3] = t[0][ 3];
8050                                 m[1][0] = t[0][ 4];
8051                                 m[1][1] = t[0][ 5];
8052                                 m[1][2] = t[0][ 6];
8053                                 m[1][3] = t[0][ 7];
8054                                 m[2][0] = t[0][ 8];
8055                                 m[2][1] = t[0][ 9];
8056                                 m[2][2] = t[0][10];
8057                                 m[2][3] = t[0][11];
8058                         }
8059                         else if (sw[2] + sw[3])
8060                         {
8061                                 // blend 4 matrices
8062                                 t[1] = b + si[1]*12;
8063                                 t[2] = b + si[2]*12;
8064                                 t[3] = b + si[3]*12;
8065                                 w[0] = sw[0] * (1.0f / 255.0f);
8066                                 w[1] = sw[1] * (1.0f / 255.0f);
8067                                 w[2] = sw[2] * (1.0f / 255.0f);
8068                                 w[3] = sw[3] * (1.0f / 255.0f);
8069                                 // blend the matrices
8070                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8071                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8072                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8073                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8074                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8075                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8076                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8077                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8078                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8079                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8080                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8081                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8082                         }
8083                         else
8084                         {
8085                                 // blend 2 matrices
8086                                 t[1] = b + si[1]*12;
8087                                 w[0] = sw[0] * (1.0f / 255.0f);
8088                                 w[1] = sw[1] * (1.0f / 255.0f);
8089                                 // blend the matrices
8090                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8091                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8092                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8093                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8094                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8095                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8096                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8097                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8098                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8099                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8100                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8101                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8102                         }
8103                         si += 4;
8104                         sw += 4;
8105                         // modify the vertex
8106                         VectorCopy(vp, tp);
8107                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8108                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8109                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8110                         vp += 3;
8111                         if (vn)
8112                         {
8113                                 // the normal transformation matrix is a set of cross products...
8114                                 CrossProduct(m[1], m[2], n[0]);
8115                                 CrossProduct(m[2], m[0], n[1]);
8116                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8117                                 VectorCopy(vn, tn);
8118                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8119                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8120                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8121                                 VectorNormalize(vn);
8122                                 vn += 3;
8123                                 if (vs)
8124                                 {
8125                                         VectorCopy(vs, ts);
8126                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8127                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8128                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8129                                         VectorNormalize(vs);
8130                                         vs += 3;
8131                                         VectorCopy(vt, tt);
8132                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8133                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8134                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8135                                         VectorNormalize(vt);
8136                                         vt += 3;
8137                                 }
8138                         }
8139                 }
8140                 rsurface.batchskeletaltransform3x4 = NULL;
8141                 rsurface.batchskeletalnumtransforms = 0;
8142         }
8143
8144         // q1bsp surfaces rendered in vertex color mode have to have colors
8145         // calculated based on lightstyles
8146         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8147         {
8148                 // generate color arrays for the surfaces in this list
8149                 int c[4];
8150                 int scale;
8151                 int size3;
8152                 const int *offsets;
8153                 const unsigned char *lm;
8154                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8155                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8156                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8157                 numvertices = 0;
8158                 for (i = 0;i < texturenumsurfaces;i++)
8159                 {
8160                         surface = texturesurfacelist[i];
8161                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8162                         surfacenumvertices = surface->num_vertices;
8163                         if (surface->lightmapinfo->samples)
8164                         {
8165                                 for (j = 0;j < surfacenumvertices;j++)
8166                                 {
8167                                         lm = surface->lightmapinfo->samples + offsets[j];
8168                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8169                                         VectorScale(lm, scale, c);
8170                                         if (surface->lightmapinfo->styles[1] != 255)
8171                                         {
8172                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8173                                                 lm += size3;
8174                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8175                                                 VectorMA(c, scale, lm, c);
8176                                                 if (surface->lightmapinfo->styles[2] != 255)
8177                                                 {
8178                                                         lm += size3;
8179                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8180                                                         VectorMA(c, scale, lm, c);
8181                                                         if (surface->lightmapinfo->styles[3] != 255)
8182                                                         {
8183                                                                 lm += size3;
8184                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8185                                                                 VectorMA(c, scale, lm, c);
8186                                                         }
8187                                                 }
8188                                         }
8189                                         c[0] >>= 7;
8190                                         c[1] >>= 7;
8191                                         c[2] >>= 7;
8192                                         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);
8193                                         numvertices++;
8194                                 }
8195                         }
8196                         else
8197                         {
8198                                 for (j = 0;j < surfacenumvertices;j++)
8199                                 {
8200                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8201                                         numvertices++;
8202                                 }
8203                         }
8204                 }
8205         }
8206
8207         // if vertices are deformed (sprite flares and things in maps, possibly
8208         // water waves, bulges and other deformations), modify the copied vertices
8209         // in place
8210         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8211         {
8212                 float scale;
8213                 switch (deform->deform)
8214                 {
8215                 default:
8216                 case Q3DEFORM_PROJECTIONSHADOW:
8217                 case Q3DEFORM_TEXT0:
8218                 case Q3DEFORM_TEXT1:
8219                 case Q3DEFORM_TEXT2:
8220                 case Q3DEFORM_TEXT3:
8221                 case Q3DEFORM_TEXT4:
8222                 case Q3DEFORM_TEXT5:
8223                 case Q3DEFORM_TEXT6:
8224                 case Q3DEFORM_TEXT7:
8225                 case Q3DEFORM_NONE:
8226                         break;
8227                 case Q3DEFORM_AUTOSPRITE:
8228                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8229                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8230                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8231                         VectorNormalize(newforward);
8232                         VectorNormalize(newright);
8233                         VectorNormalize(newup);
8234 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8235 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8236 //                      rsurface.batchvertex3f_bufferoffset = 0;
8237 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8238 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8239 //                      rsurface.batchsvector3f_bufferoffset = 0;
8240 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8241 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8242 //                      rsurface.batchtvector3f_bufferoffset = 0;
8243 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8244 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8245 //                      rsurface.batchnormal3f_bufferoffset = 0;
8246                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8247                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8248                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8249                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8250                                 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);
8251                         // a single autosprite surface can contain multiple sprites...
8252                         for (j = 0;j < batchnumvertices - 3;j += 4)
8253                         {
8254                                 VectorClear(center);
8255                                 for (i = 0;i < 4;i++)
8256                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8257                                 VectorScale(center, 0.25f, center);
8258                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8259                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8260                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8261                                 for (i = 0;i < 4;i++)
8262                                 {
8263                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8264                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8265                                 }
8266                         }
8267                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8268                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8269                         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);
8270                         break;
8271                 case Q3DEFORM_AUTOSPRITE2:
8272                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8273                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8274                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8275                         VectorNormalize(newforward);
8276                         VectorNormalize(newright);
8277                         VectorNormalize(newup);
8278 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8279 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8280 //                      rsurface.batchvertex3f_bufferoffset = 0;
8281                         {
8282                                 const float *v1, *v2;
8283                                 vec3_t start, end;
8284                                 float f, l;
8285                                 struct
8286                                 {
8287                                         float length2;
8288                                         const float *v1;
8289                                         const float *v2;
8290                                 }
8291                                 shortest[2];
8292                                 memset(shortest, 0, sizeof(shortest));
8293                                 // a single autosprite surface can contain multiple sprites...
8294                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8295                                 {
8296                                         VectorClear(center);
8297                                         for (i = 0;i < 4;i++)
8298                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8299                                         VectorScale(center, 0.25f, center);
8300                                         // find the two shortest edges, then use them to define the
8301                                         // axis vectors for rotating around the central axis
8302                                         for (i = 0;i < 6;i++)
8303                                         {
8304                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8305                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8306                                                 l = VectorDistance2(v1, v2);
8307                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8308                                                 if (v1[2] != v2[2])
8309                                                         l += (1.0f / 1024.0f);
8310                                                 if (shortest[0].length2 > l || i == 0)
8311                                                 {
8312                                                         shortest[1] = shortest[0];
8313                                                         shortest[0].length2 = l;
8314                                                         shortest[0].v1 = v1;
8315                                                         shortest[0].v2 = v2;
8316                                                 }
8317                                                 else if (shortest[1].length2 > l || i == 1)
8318                                                 {
8319                                                         shortest[1].length2 = l;
8320                                                         shortest[1].v1 = v1;
8321                                                         shortest[1].v2 = v2;
8322                                                 }
8323                                         }
8324                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8325                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8326                                         // this calculates the right vector from the shortest edge
8327                                         // and the up vector from the edge midpoints
8328                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8329                                         VectorNormalize(right);
8330                                         VectorSubtract(end, start, up);
8331                                         VectorNormalize(up);
8332                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8333                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8334                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8335                                         VectorNegate(forward, forward);
8336                                         VectorReflect(forward, 0, up, forward);
8337                                         VectorNormalize(forward);
8338                                         CrossProduct(up, forward, newright);
8339                                         VectorNormalize(newright);
8340                                         // rotate the quad around the up axis vector, this is made
8341                                         // especially easy by the fact we know the quad is flat,
8342                                         // so we only have to subtract the center position and
8343                                         // measure distance along the right vector, and then
8344                                         // multiply that by the newright vector and add back the
8345                                         // center position
8346                                         // we also need to subtract the old position to undo the
8347                                         // displacement from the center, which we do with a
8348                                         // DotProduct, the subtraction/addition of center is also
8349                                         // optimized into DotProducts here
8350                                         l = DotProduct(right, center);
8351                                         for (i = 0;i < 4;i++)
8352                                         {
8353                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8354                                                 f = DotProduct(right, v1) - l;
8355                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8356                                         }
8357                                 }
8358                         }
8359                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8360                         {
8361 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8362 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8363 //                              rsurface.batchnormal3f_bufferoffset = 0;
8364                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8365                         }
8366                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8367                         {
8368 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8369 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8370 //                              rsurface.batchsvector3f_bufferoffset = 0;
8371 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8372 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8373 //                              rsurface.batchtvector3f_bufferoffset = 0;
8374                                 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);
8375                         }
8376                         break;
8377                 case Q3DEFORM_NORMAL:
8378                         // deform the normals to make reflections wavey
8379                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8380                         rsurface.batchnormal3f_vertexbuffer = NULL;
8381                         rsurface.batchnormal3f_bufferoffset = 0;
8382                         for (j = 0;j < batchnumvertices;j++)
8383                         {
8384                                 float vertex[3];
8385                                 float *normal = rsurface.batchnormal3f + 3*j;
8386                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8387                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8388                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8389                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8390                                 VectorNormalize(normal);
8391                         }
8392                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8393                         {
8394 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8395 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8396 //                              rsurface.batchsvector3f_bufferoffset = 0;
8397 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8398 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8399 //                              rsurface.batchtvector3f_bufferoffset = 0;
8400                                 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);
8401                         }
8402                         break;
8403                 case Q3DEFORM_WAVE:
8404                         // deform vertex array to make wavey water and flags and such
8405                         waveparms[0] = deform->waveparms[0];
8406                         waveparms[1] = deform->waveparms[1];
8407                         waveparms[2] = deform->waveparms[2];
8408                         waveparms[3] = deform->waveparms[3];
8409                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8410                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8411                         // this is how a divisor of vertex influence on deformation
8412                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8413                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8414 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8415 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8416 //                      rsurface.batchvertex3f_bufferoffset = 0;
8417 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8418 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8419 //                      rsurface.batchnormal3f_bufferoffset = 0;
8420                         for (j = 0;j < batchnumvertices;j++)
8421                         {
8422                                 // if the wavefunc depends on time, evaluate it per-vertex
8423                                 if (waveparms[3])
8424                                 {
8425                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8426                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8427                                 }
8428                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8429                         }
8430                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8431                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8432                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8433                         {
8434 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8435 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8436 //                              rsurface.batchsvector3f_bufferoffset = 0;
8437 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8438 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8439 //                              rsurface.batchtvector3f_bufferoffset = 0;
8440                                 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);
8441                         }
8442                         break;
8443                 case Q3DEFORM_BULGE:
8444                         // deform vertex array to make the surface have moving bulges
8445 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8446 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8447 //                      rsurface.batchvertex3f_bufferoffset = 0;
8448 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8449 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8450 //                      rsurface.batchnormal3f_bufferoffset = 0;
8451                         for (j = 0;j < batchnumvertices;j++)
8452                         {
8453                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8454                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8455                         }
8456                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8457                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8458                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8459                         {
8460 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8461 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8462 //                              rsurface.batchsvector3f_bufferoffset = 0;
8463 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8464 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8465 //                              rsurface.batchtvector3f_bufferoffset = 0;
8466                                 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);
8467                         }
8468                         break;
8469                 case Q3DEFORM_MOVE:
8470                         // deform vertex array
8471                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8472                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8473                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8474                         VectorScale(deform->parms, scale, waveparms);
8475 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8476 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8477 //                      rsurface.batchvertex3f_bufferoffset = 0;
8478                         for (j = 0;j < batchnumvertices;j++)
8479                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8480                         break;
8481                 }
8482         }
8483
8484         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8485         {
8486         // generate texcoords based on the chosen texcoord source
8487                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8488                 {
8489                 default:
8490                 case Q3TCGEN_TEXTURE:
8491                         break;
8492                 case Q3TCGEN_LIGHTMAP:
8493         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8494         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8495         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8496                         if (rsurface.batchtexcoordlightmap2f)
8497                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8498                         break;
8499                 case Q3TCGEN_VECTOR:
8500         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8501         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8502         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8503                         for (j = 0;j < batchnumvertices;j++)
8504                         {
8505                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8506                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8507                         }
8508                         break;
8509                 case Q3TCGEN_ENVIRONMENT:
8510                         // make environment reflections using a spheremap
8511                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8512                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8513                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8514                         for (j = 0;j < batchnumvertices;j++)
8515                         {
8516                                 // identical to Q3A's method, but executed in worldspace so
8517                                 // carried models can be shiny too
8518
8519                                 float viewer[3], d, reflected[3], worldreflected[3];
8520
8521                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8522                                 // VectorNormalize(viewer);
8523
8524                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8525
8526                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8527                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8528                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8529                                 // note: this is proportinal to viewer, so we can normalize later
8530
8531                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8532                                 VectorNormalize(worldreflected);
8533
8534                                 // note: this sphere map only uses world x and z!
8535                                 // so positive and negative y will LOOK THE SAME.
8536                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8537                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8538                         }
8539                         break;
8540                 }
8541                 // the only tcmod that needs software vertex processing is turbulent, so
8542                 // check for it here and apply the changes if needed
8543                 // and we only support that as the first one
8544                 // (handling a mixture of turbulent and other tcmods would be problematic
8545                 //  without punting it entirely to a software path)
8546                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8547                 {
8548                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8549                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8550         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8551         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8552         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8553                         for (j = 0;j < batchnumvertices;j++)
8554                         {
8555                                 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);
8556                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8557                         }
8558                 }
8559         }
8560 }
8561
8562 void RSurf_DrawBatch(void)
8563 {
8564         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8565         // through the pipeline, killing it earlier in the pipeline would have
8566         // per-surface overhead rather than per-batch overhead, so it's best to
8567         // reject it here, before it hits glDraw.
8568         if (rsurface.batchnumtriangles == 0)
8569                 return;
8570 #if 0
8571         // batch debugging code
8572         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8573         {
8574                 int i;
8575                 int j;
8576                 int c;
8577                 const int *e;
8578                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8579                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8580                 {
8581                         c = e[i];
8582                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8583                         {
8584                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8585                                 {
8586                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8587                                                 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);
8588                                         break;
8589                                 }
8590                         }
8591                 }
8592         }
8593 #endif
8594         if (rsurface.batchmultidraw)
8595         {
8596                 // issue multiple draws rather than copying index data
8597                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8598                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8599                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8600                 for (i = 0;i < numsurfaces;)
8601                 {
8602                         // combine consecutive surfaces as one draw
8603                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8604                                 if (surfacelist[j] != surfacelist[k] + 1)
8605                                         break;
8606                         firstvertex = surfacelist[i]->num_firstvertex;
8607                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8608                         firsttriangle = surfacelist[i]->num_firsttriangle;
8609                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8610                         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);
8611                         i = j;
8612                 }
8613         }
8614         else
8615         {
8616                 // there is only one consecutive run of index data (may have been combined)
8617                 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);
8618         }
8619 }
8620
8621 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8622 {
8623         // pick the closest matching water plane
8624         int planeindex, vertexindex, bestplaneindex = -1;
8625         float d, bestd;
8626         vec3_t vert;
8627         const float *v;
8628         r_waterstate_waterplane_t *p;
8629         qboolean prepared = false;
8630         bestd = 0;
8631         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8632         {
8633                 if(p->camera_entity != rsurface.texture->camera_entity)
8634                         continue;
8635                 d = 0;
8636                 if(!prepared)
8637                 {
8638                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8639                         prepared = true;
8640                         if(rsurface.batchnumvertices == 0)
8641                                 break;
8642                 }
8643                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8644                 {
8645                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8646                         d += fabs(PlaneDiff(vert, &p->plane));
8647                 }
8648                 if (bestd > d || bestplaneindex < 0)
8649                 {
8650                         bestd = d;
8651                         bestplaneindex = planeindex;
8652                 }
8653         }
8654         return bestplaneindex;
8655         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8656         // this situation though, as it might be better to render single larger
8657         // batches with useless stuff (backface culled for example) than to
8658         // render multiple smaller batches
8659 }
8660
8661 void RSurf_SetupDepthAndCulling(void)
8662 {
8663         // submodels are biased to avoid z-fighting with world surfaces that they
8664         // may be exactly overlapping (avoids z-fighting artifacts on certain
8665         // doors and things in Quake maps)
8666         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8667         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8668         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8669         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8670 }
8671
8672 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8673 {
8674         int j;
8675         const float *v;
8676         float p[3], mins[3], maxs[3];
8677         int scissor[4];
8678         // transparent sky would be ridiculous
8679         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8680                 return;
8681         R_SetupShader_Generic_NoTexture(false, false);
8682         skyrenderlater = true;
8683         RSurf_SetupDepthAndCulling();
8684         GL_DepthMask(true);
8685
8686         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8687         if (r_sky_scissor.integer)
8688         {
8689                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8690                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8691                 {
8692                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8693                         if (j > 0)
8694                         {
8695                                 if (mins[0] > p[0]) mins[0] = p[0];
8696                                 if (mins[1] > p[1]) mins[1] = p[1];
8697                                 if (mins[2] > p[2]) mins[2] = p[2];
8698                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8699                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8700                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8701                         }
8702                         else
8703                         {
8704                                 VectorCopy(p, mins);
8705                                 VectorCopy(p, maxs);
8706                         }
8707                 }
8708                 if (!R_ScissorForBBox(mins, maxs, scissor))
8709                 {
8710                         if (skyscissor[2])
8711                         {
8712                                 if (skyscissor[0] > scissor[0])
8713                                 {
8714                                         skyscissor[2] += skyscissor[0] - scissor[0];
8715                                         skyscissor[0] = scissor[0];
8716                                 }
8717                                 if (skyscissor[1] > scissor[1])
8718                                 {
8719                                         skyscissor[3] += skyscissor[1] - scissor[1];
8720                                         skyscissor[1] = scissor[1];
8721                                 }
8722                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8723                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8724                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8725                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8726                         }
8727                         else
8728                                 Vector4Copy(scissor, skyscissor);
8729                 }
8730         }
8731
8732         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8733         // skymasking on them, and Quake3 never did sky masking (unlike
8734         // software Quake and software Quake2), so disable the sky masking
8735         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8736         // and skymasking also looks very bad when noclipping outside the
8737         // level, so don't use it then either.
8738         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)
8739         {
8740                 R_Mesh_ResetTextureState();
8741                 if (skyrendermasked)
8742                 {
8743                         R_SetupShader_DepthOrShadow(false, false, false);
8744                         // depth-only (masking)
8745                         GL_ColorMask(0, 0, 0, 0);
8746                         // just to make sure that braindead drivers don't draw
8747                         // anything despite that colormask...
8748                         GL_BlendFunc(GL_ZERO, GL_ONE);
8749                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8750                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8751                 }
8752                 else
8753                 {
8754                         R_SetupShader_Generic_NoTexture(false, false);
8755                         // fog sky
8756                         GL_BlendFunc(GL_ONE, GL_ZERO);
8757                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8758                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8759                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8760                 }
8761                 RSurf_DrawBatch();
8762                 if (skyrendermasked)
8763                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8764         }
8765         R_Mesh_ResetTextureState();
8766         GL_Color(1, 1, 1, 1);
8767 }
8768
8769 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8770 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8771 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8772 {
8773         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8774                 return;
8775         if (prepass)
8776         {
8777                 // render screenspace normalmap to texture
8778                 GL_DepthMask(true);
8779                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8780                 RSurf_DrawBatch();
8781                 return;
8782         }
8783
8784         // bind lightmap texture
8785
8786         // water/refraction/reflection/camera surfaces have to be handled specially
8787         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8788         {
8789                 int start, end, startplaneindex;
8790                 for (start = 0;start < texturenumsurfaces;start = end)
8791                 {
8792                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8793                         if(startplaneindex < 0)
8794                         {
8795                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8796                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8797                                 end = start + 1;
8798                                 continue;
8799                         }
8800                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8801                                 ;
8802                         // now that we have a batch using the same planeindex, render it
8803                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8804                         {
8805                                 // render water or distortion background
8806                                 GL_DepthMask(true);
8807                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8808                                 RSurf_DrawBatch();
8809                                 // blend surface on top
8810                                 GL_DepthMask(false);
8811                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8812                                 RSurf_DrawBatch();
8813                         }
8814                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8815                         {
8816                                 // render surface with reflection texture as input
8817                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8818                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8819                                 RSurf_DrawBatch();
8820                         }
8821                 }
8822                 return;
8823         }
8824
8825         // render surface batch normally
8826         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8827         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8828         RSurf_DrawBatch();
8829 }
8830
8831 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8832 {
8833         int vi;
8834         int j;
8835         int texturesurfaceindex;
8836         int k;
8837         const msurface_t *surface;
8838         float surfacecolor4f[4];
8839
8840 //      R_Mesh_ResetTextureState();
8841         R_SetupShader_Generic_NoTexture(false, false);
8842
8843         GL_BlendFunc(GL_ONE, GL_ZERO);
8844         GL_DepthMask(writedepth);
8845
8846         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8847         vi = 0;
8848         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8849         {
8850                 surface = texturesurfacelist[texturesurfaceindex];
8851                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8852                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8853                 for (j = 0;j < surface->num_vertices;j++)
8854                 {
8855                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8856                         vi++;
8857                 }
8858         }
8859         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8860         RSurf_DrawBatch();
8861 }
8862
8863 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8864 {
8865         CHECKGLERROR
8866         RSurf_SetupDepthAndCulling();
8867         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8868         {
8869                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8870                 return;
8871         }
8872         switch (vid.renderpath)
8873         {
8874         case RENDERPATH_GL32:
8875         case RENDERPATH_GLES2:
8876                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8877                 break;
8878         }
8879         CHECKGLERROR
8880 }
8881
8882 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8883 {
8884         int i, j;
8885         int texturenumsurfaces, endsurface;
8886         texture_t *texture;
8887         const msurface_t *surface;
8888         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8889
8890         RSurf_ActiveModelEntity(ent, true, true, false);
8891
8892         if (r_transparentdepthmasking.integer)
8893         {
8894                 qboolean setup = false;
8895                 for (i = 0;i < numsurfaces;i = j)
8896                 {
8897                         j = i + 1;
8898                         surface = rsurface.modelsurfaces + surfacelist[i];
8899                         texture = surface->texture;
8900                         rsurface.texture = R_GetCurrentTexture(texture);
8901                         rsurface.lightmaptexture = NULL;
8902                         rsurface.deluxemaptexture = NULL;
8903                         rsurface.uselightmaptexture = false;
8904                         // scan ahead until we find a different texture
8905                         endsurface = min(i + 1024, numsurfaces);
8906                         texturenumsurfaces = 0;
8907                         texturesurfacelist[texturenumsurfaces++] = surface;
8908                         for (;j < endsurface;j++)
8909                         {
8910                                 surface = rsurface.modelsurfaces + surfacelist[j];
8911                                 if (texture != surface->texture)
8912                                         break;
8913                                 texturesurfacelist[texturenumsurfaces++] = surface;
8914                         }
8915                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8916                                 continue;
8917                         // render the range of surfaces as depth
8918                         if (!setup)
8919                         {
8920                                 setup = true;
8921                                 GL_ColorMask(0,0,0,0);
8922                                 GL_Color(1,1,1,1);
8923                                 GL_DepthTest(true);
8924                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8925                                 GL_DepthMask(true);
8926 //                              R_Mesh_ResetTextureState();
8927                         }
8928                         RSurf_SetupDepthAndCulling();
8929                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8930                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8931                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8932                         RSurf_DrawBatch();
8933                 }
8934                 if (setup)
8935                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8936         }
8937
8938         for (i = 0;i < numsurfaces;i = j)
8939         {
8940                 j = i + 1;
8941                 surface = rsurface.modelsurfaces + surfacelist[i];
8942                 texture = surface->texture;
8943                 rsurface.texture = R_GetCurrentTexture(texture);
8944                 // scan ahead until we find a different texture
8945                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8946                 texturenumsurfaces = 0;
8947                 texturesurfacelist[texturenumsurfaces++] = surface;
8948                         rsurface.lightmaptexture = surface->lightmaptexture;
8949                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8950                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8951                         for (;j < endsurface;j++)
8952                         {
8953                                 surface = rsurface.modelsurfaces + surfacelist[j];
8954                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8955                                         break;
8956                                 texturesurfacelist[texturenumsurfaces++] = surface;
8957                         }
8958                 // render the range of surfaces
8959                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8960         }
8961         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8962 }
8963
8964 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8965 {
8966         // transparent surfaces get pushed off into the transparent queue
8967         int surfacelistindex;
8968         const msurface_t *surface;
8969         vec3_t tempcenter, center;
8970         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8971         {
8972                 surface = texturesurfacelist[surfacelistindex];
8973                 if (r_transparent_sortsurfacesbynearest.integer)
8974                 {
8975                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8976                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8977                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8978                 }
8979                 else
8980                 {
8981                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8982                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8983                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8984                 }
8985                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8986                 if (rsurface.entity->transparent_offset) // transparent offset
8987                 {
8988                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8989                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8990                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8991                 }
8992                 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);
8993         }
8994 }
8995
8996 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8997 {
8998         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8999                 return;
9000         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9001                 return;
9002         RSurf_SetupDepthAndCulling();
9003         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9004         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9005         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9006         RSurf_DrawBatch();
9007 }
9008
9009 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9010 {
9011         CHECKGLERROR
9012         if (ui)
9013                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9014         else if (depthonly)
9015                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9016         else if (prepass)
9017         {
9018                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9019                         return;
9020                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9021                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9022                 else
9023                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9024         }
9025         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9026                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9027         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9028                 return;
9029         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9030         {
9031                 // in the deferred case, transparent surfaces were queued during prepass
9032                 if (!r_shadow_usingdeferredprepass)
9033                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9034         }
9035         else
9036         {
9037                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9038                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9039         }
9040         CHECKGLERROR
9041 }
9042
9043 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9044 {
9045         int i, j;
9046         texture_t *texture;
9047         R_FrameData_SetMark();
9048         // break the surface list down into batches by texture and use of lightmapping
9049         for (i = 0;i < numsurfaces;i = j)
9050         {
9051                 j = i + 1;
9052                 // texture is the base texture pointer, rsurface.texture is the
9053                 // current frame/skin the texture is directing us to use (for example
9054                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9055                 // use skin 1 instead)
9056                 texture = surfacelist[i]->texture;
9057                 rsurface.texture = R_GetCurrentTexture(texture);
9058                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9059                 {
9060                         // if this texture is not the kind we want, skip ahead to the next one
9061                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9062                                 ;
9063                         continue;
9064                 }
9065                 if(depthonly || prepass)
9066                 {
9067                         rsurface.lightmaptexture = NULL;
9068                         rsurface.deluxemaptexture = NULL;
9069                         rsurface.uselightmaptexture = false;
9070                         // simply scan ahead until we find a different texture or lightmap state
9071                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9072                                 ;
9073                 }
9074                 else
9075                 {
9076                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9077                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9078                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9079                         // simply scan ahead until we find a different texture or lightmap state
9080                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9081                                 ;
9082                 }
9083                 // render the range of surfaces
9084                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9085         }
9086         R_FrameData_ReturnToMark();
9087 }
9088
9089 float locboxvertex3f[6*4*3] =
9090 {
9091         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9092         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9093         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9094         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9095         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9096         1,0,0, 0,0,0, 0,1,0, 1,1,0
9097 };
9098
9099 unsigned short locboxelements[6*2*3] =
9100 {
9101          0, 1, 2, 0, 2, 3,
9102          4, 5, 6, 4, 6, 7,
9103          8, 9,10, 8,10,11,
9104         12,13,14, 12,14,15,
9105         16,17,18, 16,18,19,
9106         20,21,22, 20,22,23
9107 };
9108
9109 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9110 {
9111         int i, j;
9112         cl_locnode_t *loc = (cl_locnode_t *)ent;
9113         vec3_t mins, size;
9114         float vertex3f[6*4*3];
9115         CHECKGLERROR
9116         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9117         GL_DepthMask(false);
9118         GL_DepthRange(0, 1);
9119         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9120         GL_DepthTest(true);
9121         GL_CullFace(GL_NONE);
9122         R_EntityMatrix(&identitymatrix);
9123
9124 //      R_Mesh_ResetTextureState();
9125
9126         i = surfacelist[0];
9127         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9128                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9129                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9130                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9131
9132         if (VectorCompare(loc->mins, loc->maxs))
9133         {
9134                 VectorSet(size, 2, 2, 2);
9135                 VectorMA(loc->mins, -0.5f, size, mins);
9136         }
9137         else
9138         {
9139                 VectorCopy(loc->mins, mins);
9140                 VectorSubtract(loc->maxs, loc->mins, size);
9141         }
9142
9143         for (i = 0;i < 6*4*3;)
9144                 for (j = 0;j < 3;j++, i++)
9145                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9146
9147         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9148         R_SetupShader_Generic_NoTexture(false, false);
9149         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9150 }
9151
9152 void R_DrawLocs(void)
9153 {
9154         int index;
9155         cl_locnode_t *loc, *nearestloc;
9156         vec3_t center;
9157         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9158         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9159         {
9160                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9161                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9162         }
9163 }
9164
9165 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9166 {
9167         if (decalsystem->decals)
9168                 Mem_Free(decalsystem->decals);
9169         memset(decalsystem, 0, sizeof(*decalsystem));
9170 }
9171
9172 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)
9173 {
9174         tridecal_t *decal;
9175         tridecal_t *decals;
9176         int i;
9177
9178         // expand or initialize the system
9179         if (decalsystem->maxdecals <= decalsystem->numdecals)
9180         {
9181                 decalsystem_t old = *decalsystem;
9182                 qboolean useshortelements;
9183                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9184                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9185                 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)));
9186                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9187                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9188                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9189                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9190                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9191                 if (decalsystem->numdecals)
9192                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9193                 if (old.decals)
9194                         Mem_Free(old.decals);
9195                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9196                         decalsystem->element3i[i] = i;
9197                 if (useshortelements)
9198                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9199                                 decalsystem->element3s[i] = i;
9200         }
9201
9202         // grab a decal and search for another free slot for the next one
9203         decals = decalsystem->decals;
9204         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9205         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9206                 ;
9207         decalsystem->freedecal = i;
9208         if (decalsystem->numdecals <= i)
9209                 decalsystem->numdecals = i + 1;
9210
9211         // initialize the decal
9212         decal->lived = 0;
9213         decal->triangleindex = triangleindex;
9214         decal->surfaceindex = surfaceindex;
9215         decal->decalsequence = decalsequence;
9216         decal->color4f[0][0] = c0[0];
9217         decal->color4f[0][1] = c0[1];
9218         decal->color4f[0][2] = c0[2];
9219         decal->color4f[0][3] = 1;
9220         decal->color4f[1][0] = c1[0];
9221         decal->color4f[1][1] = c1[1];
9222         decal->color4f[1][2] = c1[2];
9223         decal->color4f[1][3] = 1;
9224         decal->color4f[2][0] = c2[0];
9225         decal->color4f[2][1] = c2[1];
9226         decal->color4f[2][2] = c2[2];
9227         decal->color4f[2][3] = 1;
9228         decal->vertex3f[0][0] = v0[0];
9229         decal->vertex3f[0][1] = v0[1];
9230         decal->vertex3f[0][2] = v0[2];
9231         decal->vertex3f[1][0] = v1[0];
9232         decal->vertex3f[1][1] = v1[1];
9233         decal->vertex3f[1][2] = v1[2];
9234         decal->vertex3f[2][0] = v2[0];
9235         decal->vertex3f[2][1] = v2[1];
9236         decal->vertex3f[2][2] = v2[2];
9237         decal->texcoord2f[0][0] = t0[0];
9238         decal->texcoord2f[0][1] = t0[1];
9239         decal->texcoord2f[1][0] = t1[0];
9240         decal->texcoord2f[1][1] = t1[1];
9241         decal->texcoord2f[2][0] = t2[0];
9242         decal->texcoord2f[2][1] = t2[1];
9243         TriangleNormal(v0, v1, v2, decal->plane);
9244         VectorNormalize(decal->plane);
9245         decal->plane[3] = DotProduct(v0, decal->plane);
9246 }
9247
9248 extern cvar_t cl_decals_bias;
9249 extern cvar_t cl_decals_models;
9250 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9251 // baseparms, parms, temps
9252 static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9253 {
9254         int cornerindex;
9255         int index;
9256         float v[9][3];
9257         const float *vertex3f;
9258         const float *normal3f;
9259         int numpoints;
9260         float points[2][9][3];
9261         float temp[3];
9262         float tc[9][2];
9263         float f;
9264         float c[9][4];
9265         const int *e;
9266
9267         e = rsurface.modelelement3i + 3*triangleindex;
9268
9269         vertex3f = rsurface.modelvertex3f;
9270         normal3f = rsurface.modelnormal3f;
9271
9272         if (normal3f)
9273         {
9274                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9275                 {
9276                         index = 3*e[cornerindex];
9277                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9278                 }
9279         }
9280         else
9281         {
9282                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9283                 {
9284                         index = 3*e[cornerindex];
9285                         VectorCopy(vertex3f + index, v[cornerindex]);
9286                 }
9287         }
9288
9289         // cull backfaces
9290         //TriangleNormal(v[0], v[1], v[2], normal);
9291         //if (DotProduct(normal, localnormal) < 0.0f)
9292         //      continue;
9293         // clip by each of the box planes formed from the projection matrix
9294         // if anything survives, we emit the decal
9295         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]);
9296         if (numpoints < 3)
9297                 return;
9298         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]);
9299         if (numpoints < 3)
9300                 return;
9301         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]);
9302         if (numpoints < 3)
9303                 return;
9304         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]);
9305         if (numpoints < 3)
9306                 return;
9307         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]);
9308         if (numpoints < 3)
9309                 return;
9310         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]);
9311         if (numpoints < 3)
9312                 return;
9313         // some part of the triangle survived, so we have to accept it...
9314         if (dynamic)
9315         {
9316                 // dynamic always uses the original triangle
9317                 numpoints = 3;
9318                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9319                 {
9320                         index = 3*e[cornerindex];
9321                         VectorCopy(vertex3f + index, v[cornerindex]);
9322                 }
9323         }
9324         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9325         {
9326                 // convert vertex positions to texcoords
9327                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9328                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9329                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9330                 // calculate distance fade from the projection origin
9331                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9332                 f = bound(0.0f, f, 1.0f);
9333                 c[cornerindex][0] = r * f;
9334                 c[cornerindex][1] = g * f;
9335                 c[cornerindex][2] = b * f;
9336                 c[cornerindex][3] = 1.0f;
9337                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9338         }
9339         if (dynamic)
9340                 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);
9341         else
9342                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9343                         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);
9344 }
9345 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)
9346 {
9347         matrix4x4_t projection;
9348         decalsystem_t *decalsystem;
9349         qboolean dynamic;
9350         dp_model_t *model;
9351         const msurface_t *surface;
9352         const msurface_t *surfaces;
9353         const int *surfacelist;
9354         const texture_t *texture;
9355         int numtriangles;
9356         int numsurfacelist;
9357         int surfacelistindex;
9358         int surfaceindex;
9359         int triangleindex;
9360         float localorigin[3];
9361         float localnormal[3];
9362         float localmins[3];
9363         float localmaxs[3];
9364         float localsize;
9365         //float normal[3];
9366         float planes[6][4];
9367         float angles[3];
9368         bih_t *bih;
9369         int bih_triangles_count;
9370         int bih_triangles[256];
9371         int bih_surfaces[256];
9372
9373         decalsystem = &ent->decalsystem;
9374         model = ent->model;
9375         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9376         {
9377                 R_DecalSystem_Reset(&ent->decalsystem);
9378                 return;
9379         }
9380
9381         if (!model->brush.data_leafs && !cl_decals_models.integer)
9382         {
9383                 if (decalsystem->model)
9384                         R_DecalSystem_Reset(decalsystem);
9385                 return;
9386         }
9387
9388         if (decalsystem->model != model)
9389                 R_DecalSystem_Reset(decalsystem);
9390         decalsystem->model = model;
9391
9392         RSurf_ActiveModelEntity(ent, true, false, false);
9393
9394         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9395         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9396         VectorNormalize(localnormal);
9397         localsize = worldsize*rsurface.inversematrixscale;
9398         localmins[0] = localorigin[0] - localsize;
9399         localmins[1] = localorigin[1] - localsize;
9400         localmins[2] = localorigin[2] - localsize;
9401         localmaxs[0] = localorigin[0] + localsize;
9402         localmaxs[1] = localorigin[1] + localsize;
9403         localmaxs[2] = localorigin[2] + localsize;
9404
9405         //VectorCopy(localnormal, planes[4]);
9406         //VectorVectors(planes[4], planes[2], planes[0]);
9407         AnglesFromVectors(angles, localnormal, NULL, false);
9408         AngleVectors(angles, planes[0], planes[2], planes[4]);
9409         VectorNegate(planes[0], planes[1]);
9410         VectorNegate(planes[2], planes[3]);
9411         VectorNegate(planes[4], planes[5]);
9412         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9413         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9414         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9415         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9416         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9417         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9418
9419 #if 1
9420 // works
9421 {
9422         matrix4x4_t forwardprojection;
9423         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9424         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9425 }
9426 #else
9427 // broken
9428 {
9429         float projectionvector[4][3];
9430         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9431         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9432         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9433         projectionvector[0][0] = planes[0][0] * ilocalsize;
9434         projectionvector[0][1] = planes[1][0] * ilocalsize;
9435         projectionvector[0][2] = planes[2][0] * ilocalsize;
9436         projectionvector[1][0] = planes[0][1] * ilocalsize;
9437         projectionvector[1][1] = planes[1][1] * ilocalsize;
9438         projectionvector[1][2] = planes[2][1] * ilocalsize;
9439         projectionvector[2][0] = planes[0][2] * ilocalsize;
9440         projectionvector[2][1] = planes[1][2] * ilocalsize;
9441         projectionvector[2][2] = planes[2][2] * ilocalsize;
9442         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9443         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9444         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9445         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9446 }
9447 #endif
9448
9449         dynamic = model->surfmesh.isanimated;
9450         numsurfacelist = model->nummodelsurfaces;
9451         surfacelist = model->sortedmodelsurfaces;
9452         surfaces = model->data_surfaces;
9453
9454         bih = NULL;
9455         bih_triangles_count = -1;
9456         if(!dynamic)
9457         {
9458                 if(model->render_bih.numleafs)
9459                         bih = &model->render_bih;
9460                 else if(model->collision_bih.numleafs)
9461                         bih = &model->collision_bih;
9462         }
9463         if(bih)
9464                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9465         if(bih_triangles_count == 0)
9466                 return;
9467         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9468                 return;
9469         if(bih_triangles_count > 0)
9470         {
9471                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9472                 {
9473                         surfaceindex = bih_surfaces[triangleindex];
9474                         surface = surfaces + surfaceindex;
9475                         texture = surface->texture;
9476                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9477                                 continue;
9478                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9479                                 continue;
9480                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9481                 }
9482         }
9483         else
9484         {
9485                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9486                 {
9487                         surfaceindex = surfacelist[surfacelistindex];
9488                         surface = surfaces + surfaceindex;
9489                         // check cull box first because it rejects more than any other check
9490                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9491                                 continue;
9492                         // skip transparent surfaces
9493                         texture = surface->texture;
9494                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9495                                 continue;
9496                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9497                                 continue;
9498                         numtriangles = surface->num_triangles;
9499                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9500                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9501                 }
9502         }
9503 }
9504
9505 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9506 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)
9507 {
9508         int renderentityindex;
9509         float worldmins[3];
9510         float worldmaxs[3];
9511         entity_render_t *ent;
9512
9513         worldmins[0] = worldorigin[0] - worldsize;
9514         worldmins[1] = worldorigin[1] - worldsize;
9515         worldmins[2] = worldorigin[2] - worldsize;
9516         worldmaxs[0] = worldorigin[0] + worldsize;
9517         worldmaxs[1] = worldorigin[1] + worldsize;
9518         worldmaxs[2] = worldorigin[2] + worldsize;
9519
9520         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9521
9522         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9523         {
9524                 ent = r_refdef.scene.entities[renderentityindex];
9525                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9526                         continue;
9527
9528                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9529         }
9530 }
9531
9532 typedef struct r_decalsystem_splatqueue_s
9533 {
9534         vec3_t worldorigin;
9535         vec3_t worldnormal;
9536         float color[4];
9537         float tcrange[4];
9538         float worldsize;
9539         unsigned int decalsequence;
9540 }
9541 r_decalsystem_splatqueue_t;
9542
9543 int r_decalsystem_numqueued = 0;
9544 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9545
9546 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)
9547 {
9548         r_decalsystem_splatqueue_t *queue;
9549
9550         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9551                 return;
9552
9553         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9554         VectorCopy(worldorigin, queue->worldorigin);
9555         VectorCopy(worldnormal, queue->worldnormal);
9556         Vector4Set(queue->color, r, g, b, a);
9557         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9558         queue->worldsize = worldsize;
9559         queue->decalsequence = cl.decalsequence++;
9560 }
9561
9562 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9563 {
9564         int i;
9565         r_decalsystem_splatqueue_t *queue;
9566
9567         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9568                 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);
9569         r_decalsystem_numqueued = 0;
9570 }
9571
9572 extern cvar_t cl_decals_max;
9573 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9574 {
9575         int i;
9576         decalsystem_t *decalsystem = &ent->decalsystem;
9577         int numdecals;
9578         unsigned int killsequence;
9579         tridecal_t *decal;
9580         float frametime;
9581         float lifetime;
9582
9583         if (!decalsystem->numdecals)
9584                 return;
9585
9586         if (r_showsurfaces.integer)
9587                 return;
9588
9589         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9590         {
9591                 R_DecalSystem_Reset(decalsystem);
9592                 return;
9593         }
9594
9595         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9596         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9597
9598         if (decalsystem->lastupdatetime)
9599                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9600         else
9601                 frametime = 0;
9602         decalsystem->lastupdatetime = r_refdef.scene.time;
9603         numdecals = decalsystem->numdecals;
9604
9605         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9606         {
9607                 if (decal->color4f[0][3])
9608                 {
9609                         decal->lived += frametime;
9610                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9611                         {
9612                                 memset(decal, 0, sizeof(*decal));
9613                                 if (decalsystem->freedecal > i)
9614                                         decalsystem->freedecal = i;
9615                         }
9616                 }
9617         }
9618         decal = decalsystem->decals;
9619         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9620                 numdecals--;
9621
9622         // collapse the array by shuffling the tail decals into the gaps
9623         for (;;)
9624         {
9625                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9626                         decalsystem->freedecal++;
9627                 if (decalsystem->freedecal == numdecals)
9628                         break;
9629                 decal[decalsystem->freedecal] = decal[--numdecals];
9630         }
9631
9632         decalsystem->numdecals = numdecals;
9633
9634         if (numdecals <= 0)
9635         {
9636                 // if there are no decals left, reset decalsystem
9637                 R_DecalSystem_Reset(decalsystem);
9638         }
9639 }
9640
9641 extern skinframe_t *decalskinframe;
9642 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9643 {
9644         int i;
9645         decalsystem_t *decalsystem = &ent->decalsystem;
9646         int numdecals;
9647         tridecal_t *decal;
9648         float faderate;
9649         float alpha;
9650         float *v3f;
9651         float *c4f;
9652         float *t2f;
9653         const int *e;
9654         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9655         int numtris = 0;
9656
9657         numdecals = decalsystem->numdecals;
9658         if (!numdecals)
9659                 return;
9660
9661         if (r_showsurfaces.integer)
9662                 return;
9663
9664         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9665         {
9666                 R_DecalSystem_Reset(decalsystem);
9667                 return;
9668         }
9669
9670         // if the model is static it doesn't matter what value we give for
9671         // wantnormals and wanttangents, so this logic uses only rules applicable
9672         // to a model, knowing that they are meaningless otherwise
9673         RSurf_ActiveModelEntity(ent, false, false, false);
9674
9675         decalsystem->lastupdatetime = r_refdef.scene.time;
9676
9677         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9678
9679         // update vertex positions for animated models
9680         v3f = decalsystem->vertex3f;
9681         c4f = decalsystem->color4f;
9682         t2f = decalsystem->texcoord2f;
9683         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9684         {
9685                 if (!decal->color4f[0][3])
9686                         continue;
9687
9688                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9689                         continue;
9690
9691                 // skip backfaces
9692                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9693                         continue;
9694
9695                 // update color values for fading decals
9696                 if (decal->lived >= cl_decals_time.value)
9697                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9698                 else
9699                         alpha = 1.0f;
9700
9701                 c4f[ 0] = decal->color4f[0][0] * alpha;
9702                 c4f[ 1] = decal->color4f[0][1] * alpha;
9703                 c4f[ 2] = decal->color4f[0][2] * alpha;
9704                 c4f[ 3] = 1;
9705                 c4f[ 4] = decal->color4f[1][0] * alpha;
9706                 c4f[ 5] = decal->color4f[1][1] * alpha;
9707                 c4f[ 6] = decal->color4f[1][2] * alpha;
9708                 c4f[ 7] = 1;
9709                 c4f[ 8] = decal->color4f[2][0] * alpha;
9710                 c4f[ 9] = decal->color4f[2][1] * alpha;
9711                 c4f[10] = decal->color4f[2][2] * alpha;
9712                 c4f[11] = 1;
9713
9714                 t2f[0] = decal->texcoord2f[0][0];
9715                 t2f[1] = decal->texcoord2f[0][1];
9716                 t2f[2] = decal->texcoord2f[1][0];
9717                 t2f[3] = decal->texcoord2f[1][1];
9718                 t2f[4] = decal->texcoord2f[2][0];
9719                 t2f[5] = decal->texcoord2f[2][1];
9720
9721                 // update vertex positions for animated models
9722                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9723                 {
9724                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9725                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9726                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9727                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9728                 }
9729                 else
9730                 {
9731                         VectorCopy(decal->vertex3f[0], v3f);
9732                         VectorCopy(decal->vertex3f[1], v3f + 3);
9733                         VectorCopy(decal->vertex3f[2], v3f + 6);
9734                 }
9735
9736                 if (r_refdef.fogenabled)
9737                 {
9738                         alpha = RSurf_FogVertex(v3f);
9739                         VectorScale(c4f, alpha, c4f);
9740                         alpha = RSurf_FogVertex(v3f + 3);
9741                         VectorScale(c4f + 4, alpha, c4f + 4);
9742                         alpha = RSurf_FogVertex(v3f + 6);
9743                         VectorScale(c4f + 8, alpha, c4f + 8);
9744                 }
9745
9746                 v3f += 9;
9747                 c4f += 12;
9748                 t2f += 6;
9749                 numtris++;
9750         }
9751
9752         if (numtris > 0)
9753         {
9754                 r_refdef.stats[r_stat_drawndecals] += numtris;
9755
9756                 // now render the decals all at once
9757                 // (this assumes they all use one particle font texture!)
9758                 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);
9759 //              R_Mesh_ResetTextureState();
9760                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9761                 GL_DepthMask(false);
9762                 GL_DepthRange(0, 1);
9763                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9764                 GL_DepthTest(true);
9765                 GL_CullFace(GL_NONE);
9766                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9767                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9768                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9769         }
9770 }
9771
9772 static void R_DrawModelDecals(void)
9773 {
9774         int i, numdecals;
9775
9776         // fade faster when there are too many decals
9777         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9778         for (i = 0;i < r_refdef.scene.numentities;i++)
9779                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9780
9781         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9782         for (i = 0;i < r_refdef.scene.numentities;i++)
9783                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9784                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9785
9786         R_DecalSystem_ApplySplatEntitiesQueue();
9787
9788         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9789         for (i = 0;i < r_refdef.scene.numentities;i++)
9790                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9791
9792         r_refdef.stats[r_stat_totaldecals] += numdecals;
9793
9794         if (r_showsurfaces.integer || !r_drawdecals.integer)
9795                 return;
9796
9797         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9798
9799         for (i = 0;i < r_refdef.scene.numentities;i++)
9800         {
9801                 if (!r_refdef.viewcache.entityvisible[i])
9802                         continue;
9803                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9804                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9805         }
9806 }
9807
9808 static void R_DrawDebugModel(void)
9809 {
9810         entity_render_t *ent = rsurface.entity;
9811         int i, j, flagsmask;
9812         const msurface_t *surface;
9813         dp_model_t *model = ent->model;
9814
9815         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9816                 return;
9817
9818         if (r_showoverdraw.value > 0)
9819         {
9820                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9821                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9822                 R_SetupShader_Generic_NoTexture(false, false);
9823                 GL_DepthTest(false);
9824                 GL_DepthMask(false);
9825                 GL_DepthRange(0, 1);
9826                 GL_BlendFunc(GL_ONE, GL_ONE);
9827                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9828                 {
9829                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9830                                 continue;
9831                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9832                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9833                         {
9834                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9835                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9836                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9837                                         GL_Color(c, 0, 0, 1.0f);
9838                                 else if (ent == r_refdef.scene.worldentity)
9839                                         GL_Color(c, c, c, 1.0f);
9840                                 else
9841                                         GL_Color(0, c, 0, 1.0f);
9842                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9843                                 RSurf_DrawBatch();
9844                         }
9845                 }
9846                 rsurface.texture = NULL;
9847         }
9848
9849         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9850
9851 //      R_Mesh_ResetTextureState();
9852         R_SetupShader_Generic_NoTexture(false, false);
9853         GL_DepthRange(0, 1);
9854         GL_DepthTest(!r_showdisabledepthtest.integer);
9855         GL_DepthMask(false);
9856         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9857
9858         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9859         {
9860                 int triangleindex;
9861                 int bihleafindex;
9862                 qboolean cullbox = false;
9863                 const q3mbrush_t *brush;
9864                 const bih_t *bih = &model->collision_bih;
9865                 const bih_leaf_t *bihleaf;
9866                 float vertex3f[3][3];
9867                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9868                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9869                 {
9870                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9871                                 continue;
9872                         switch (bihleaf->type)
9873                         {
9874                         case BIH_BRUSH:
9875                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9876                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9877                                 {
9878                                         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);
9879                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9880                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9881                                 }
9882                                 break;
9883                         case BIH_COLLISIONTRIANGLE:
9884                                 triangleindex = bihleaf->itemindex;
9885                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9886                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9887                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9888                                 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);
9889                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9890                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9891                                 break;
9892                         case BIH_RENDERTRIANGLE:
9893                                 triangleindex = bihleaf->itemindex;
9894                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9895                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9896                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9897                                 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);
9898                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9899                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9900                                 break;
9901                         }
9902                 }
9903         }
9904
9905         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9906
9907 #ifndef USE_GLES2
9908         if (r_showtris.value > 0 && qglPolygonMode)
9909         {
9910                 if (r_showdisabledepthtest.integer)
9911                 {
9912                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9913                         GL_DepthMask(false);
9914                 }
9915                 else
9916                 {
9917                         GL_BlendFunc(GL_ONE, GL_ZERO);
9918                         GL_DepthMask(true);
9919                 }
9920                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9921                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9922                 {
9923                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9924                                 continue;
9925                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9926                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9927                         {
9928                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9929                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9930                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9931                                 else if (ent == r_refdef.scene.worldentity)
9932                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9933                                 else
9934                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9935                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9936                                 RSurf_DrawBatch();
9937                         }
9938                 }
9939                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9940                 rsurface.texture = NULL;
9941         }
9942
9943 # if 0
9944         // FIXME!  implement r_shownormals with just triangles
9945         if (r_shownormals.value != 0 && qglBegin)
9946         {
9947                 int l, k;
9948                 vec3_t v;
9949                 if (r_showdisabledepthtest.integer)
9950                 {
9951                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9952                         GL_DepthMask(false);
9953                 }
9954                 else
9955                 {
9956                         GL_BlendFunc(GL_ONE, GL_ZERO);
9957                         GL_DepthMask(true);
9958                 }
9959                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9960                 {
9961                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9962                                 continue;
9963                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9964                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9965                         {
9966                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9967                                 qglBegin(GL_LINES);
9968                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9969                                 {
9970                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9971                                         {
9972                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9973                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9974                                                 qglVertex3f(v[0], v[1], v[2]);
9975                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9976                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9977                                                 qglVertex3f(v[0], v[1], v[2]);
9978                                         }
9979                                 }
9980                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9981                                 {
9982                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9983                                         {
9984                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9985                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9986                                                 qglVertex3f(v[0], v[1], v[2]);
9987                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9988                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9989                                                 qglVertex3f(v[0], v[1], v[2]);
9990                                         }
9991                                 }
9992                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9993                                 {
9994                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9995                                         {
9996                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9997                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9998                                                 qglVertex3f(v[0], v[1], v[2]);
9999                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10000                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10001                                                 qglVertex3f(v[0], v[1], v[2]);
10002                                         }
10003                                 }
10004                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10005                                 {
10006                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10007                                         {
10008                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10009                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10010                                                 qglVertex3f(v[0], v[1], v[2]);
10011                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10012                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10013                                                 qglVertex3f(v[0], v[1], v[2]);
10014                                         }
10015                                 }
10016                                 qglEnd();
10017                                 CHECKGLERROR
10018                         }
10019                 }
10020                 rsurface.texture = NULL;
10021         }
10022 # endif
10023 #endif
10024 }
10025
10026 int r_maxsurfacelist = 0;
10027 const msurface_t **r_surfacelist = NULL;
10028 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10029 {
10030         int i, j, endj, flagsmask;
10031         dp_model_t *model = ent->model;
10032         msurface_t *surfaces;
10033         unsigned char *update;
10034         int numsurfacelist = 0;
10035         if (model == NULL)
10036                 return;
10037
10038         if (r_maxsurfacelist < model->num_surfaces)
10039         {
10040                 r_maxsurfacelist = model->num_surfaces;
10041                 if (r_surfacelist)
10042                         Mem_Free((msurface_t **)r_surfacelist);
10043                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10044         }
10045
10046         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10047                 RSurf_ActiveModelEntity(ent, false, false, false);
10048         else if (prepass)
10049                 RSurf_ActiveModelEntity(ent, true, true, true);
10050         else if (depthonly)
10051                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10052         else
10053                 RSurf_ActiveModelEntity(ent, true, true, false);
10054
10055         surfaces = model->data_surfaces;
10056         update = model->brushq1.lightmapupdateflags;
10057
10058         // update light styles
10059         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10060         {
10061                 model_brush_lightstyleinfo_t *style;
10062                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10063                 {
10064                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10065                         {
10066                                 int *list = style->surfacelist;
10067                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10068                                 for (j = 0;j < style->numsurfaces;j++)
10069                                         update[list[j]] = true;
10070                         }
10071                 }
10072         }
10073
10074         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10075
10076         if (debug)
10077         {
10078                 R_DrawDebugModel();
10079                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10080                 return;
10081         }
10082
10083         rsurface.lightmaptexture = NULL;
10084         rsurface.deluxemaptexture = NULL;
10085         rsurface.uselightmaptexture = false;
10086         rsurface.texture = NULL;
10087         rsurface.rtlight = NULL;
10088         numsurfacelist = 0;
10089         // add visible surfaces to draw list
10090         if (ent == r_refdef.scene.worldentity)
10091         {
10092                 // for the world entity, check surfacevisible
10093                 for (i = 0;i < model->nummodelsurfaces;i++)
10094                 {
10095                         j = model->sortedmodelsurfaces[i];
10096                         if (r_refdef.viewcache.world_surfacevisible[j])
10097                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10098                 }
10099         }
10100         else if (ui)
10101         {
10102                 // for ui we have to preserve the order of surfaces
10103                 for (i = 0; i < model->nummodelsurfaces; i++)
10104                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10105         }
10106         else
10107         {
10108                 // add all surfaces
10109                 for (i = 0; i < model->nummodelsurfaces; i++)
10110                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10111         }
10112         // don't do anything if there were no surfaces
10113         if (!numsurfacelist)
10114         {
10115                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10116                 return;
10117         }
10118         // update lightmaps if needed
10119         if (update)
10120         {
10121                 int updated = 0;
10122                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10123                 {
10124                         if (update[j])
10125                         {
10126                                 updated++;
10127                                 R_BuildLightMap(ent, surfaces + j);
10128                         }
10129                 }
10130         }
10131
10132         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10133
10134         // add to stats if desired
10135         if (r_speeds.integer && !skysurfaces && !depthonly)
10136         {
10137                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10138                 for (j = 0;j < numsurfacelist;j++)
10139                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10140         }
10141
10142         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10143 }
10144
10145 void R_DebugLine(vec3_t start, vec3_t end)
10146 {
10147         dp_model_t *mod = CL_Mesh_UI();
10148         msurface_t *surf;
10149         int e0, e1, e2, e3;
10150         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10151         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10152         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10153         vec4_t w[2], s[2];
10154
10155         // transform to screen coords first
10156         Vector4Set(w[0], start[0], start[1], start[2], 1);
10157         Vector4Set(w[1], end[0], end[1], end[2], 1);
10158         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10159         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10160         x1 = s[0][0] * vid_conwidth.value / vid.width;
10161         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10162         x2 = s[1][0] * vid_conwidth.value / vid.width;
10163         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10164         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10165
10166         // add the line to the UI mesh for drawing later
10167
10168         // width is measured in real pixels
10169         if (fabs(x2 - x1) > fabs(y2 - y1))
10170         {
10171                 offsetx = 0;
10172                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10173         }
10174         else
10175         {
10176                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10177                 offsety = 0;
10178         }
10179         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);
10180         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10181         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10182         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10183         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10184         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10185         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10186
10187 }
10188
10189
10190 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10191 {
10192         static texture_t texture;
10193
10194         // fake enough texture and surface state to render this geometry
10195
10196         texture.update_lastrenderframe = -1; // regenerate this texture
10197         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10198         texture.basealpha = 1.0f;
10199         texture.currentskinframe = skinframe;
10200         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10201         texture.offsetmapping = OFFSETMAPPING_OFF;
10202         texture.offsetscale = 1;
10203         texture.specularscalemod = 1;
10204         texture.specularpowermod = 1;
10205         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10206
10207         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10208 }
10209
10210 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass, qboolean ui)
10211 {
10212         static msurface_t surface;
10213         const msurface_t *surfacelist = &surface;
10214
10215         // fake enough texture and surface state to render this geometry
10216         surface.texture = texture;
10217         surface.num_triangles = numtriangles;
10218         surface.num_firsttriangle = firsttriangle;
10219         surface.num_vertices = numvertices;
10220         surface.num_firstvertex = firstvertex;
10221
10222         // now render it
10223         rsurface.texture = R_GetCurrentTexture(surface.texture);
10224         rsurface.lightmaptexture = NULL;
10225         rsurface.deluxemaptexture = NULL;
10226         rsurface.uselightmaptexture = false;
10227         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10228 }