]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Implement EXT_WRATH fields
[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_color_lut = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_postprocess_color_lut", "", "color lookup table for post, empty string for default"};
186 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)"};
187 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)"};
188 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)"};
189 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)"};
190 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)"};
191 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)"};
192 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)"};
193 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)"};
194 cvar_t r_colorfringe = {CVAR_CLIENT | CVAR_SAVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
195
196 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)"};
197 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)"};
198 cvar_t r_water_clippingplanebias = {CVAR_CLIENT | CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
199 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"};
200 cvar_t r_water_refractdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
201 cvar_t r_water_reflectdistort = {CVAR_CLIENT | CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
202 cvar_t r_water_scissormode = {CVAR_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
203 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"};
204 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"};
205
206 cvar_t r_lerpsprites = {CVAR_CLIENT | CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
207 cvar_t r_lerpmodels = {CVAR_CLIENT | CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
208 cvar_t r_lerplightstyles = {CVAR_CLIENT | CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
209 cvar_t r_waterscroll = {CVAR_CLIENT | CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
210
211 cvar_t r_bloom = {CVAR_CLIENT | CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
212 cvar_t r_bloom_colorscale = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
213
214 cvar_t r_bloom_brighten = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
215 cvar_t r_bloom_blur = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
216 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)"};
217 cvar_t r_bloom_colorexponent = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
218 cvar_t r_bloom_colorsubtract = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
219 cvar_t r_bloom_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
220
221 cvar_t r_hdr_scenebrightness = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
222 cvar_t r_hdr_glowintensity = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
223 cvar_t r_hdr_irisadaptation = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
224 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
225 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
226 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_value = {CVAR_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
228 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_CLIENT | CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
229 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"};
230 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"};
231
232 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"};
233
234 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"};
235
236 cvar_t gl_lightmaps = {CVAR_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
237
238 cvar_t r_test = {CVAR_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
239
240 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)"};
241 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)"};
242 cvar_t r_batch_debugdynamicvertexpath = {CVAR_CLIENT | CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
243 cvar_t r_batch_dynamicbuffer = {CVAR_CLIENT | CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
244
245 cvar_t r_glsl_saturation = {CVAR_CLIENT | CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
246 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"};
247
248 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."};
249
250 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)"};
251 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
252 {
253         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
254         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
255         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
256         {CVAR_CLIENT | CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
257 };
258
259 extern cvar_t v_glslgamma_2d;
260
261 extern qboolean v_flipped_state;
262
263 r_framebufferstate_t r_fb;
264
265 /// shadow volume bsp struct with automatically growing nodes buffer
266 svbsp_t r_svbsp;
267
268 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
269
270 rtexture_t *r_texture_blanknormalmap;
271 rtexture_t *r_texture_white;
272 rtexture_t *r_texture_grey128;
273 rtexture_t *r_texture_black;
274 rtexture_t *r_texture_notexture;
275 rtexture_t *r_texture_whitecube;
276 rtexture_t *r_texture_normalizationcube;
277 rtexture_t *r_texture_fogattenuation;
278 rtexture_t *r_texture_fogheighttexture;
279 rtexture_t *r_texture_gammaramps;
280 rtexture_t *r_texture_lut;
281 rtexture_t *r_texture_lut_default;
282 cachepic_t *r_texture_lut_pic;
283 unsigned int r_texture_gammaramps_serial;
284 //rtexture_t *r_texture_fogintensity;
285 rtexture_t *r_texture_reflectcube;
286
287 // TODO: hash lookups?
288 typedef struct cubemapinfo_s
289 {
290         char basename[64];
291         rtexture_t *texture;
292 }
293 cubemapinfo_t;
294
295 int r_texture_numcubemaps;
296 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
297
298 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
299 unsigned int r_numqueries;
300 unsigned int r_maxqueries;
301
302 typedef struct r_qwskincache_s
303 {
304         char name[MAX_QPATH];
305         skinframe_t *skinframe;
306 }
307 r_qwskincache_t;
308
309 static r_qwskincache_t *r_qwskincache;
310 static int r_qwskincache_size;
311
312 /// vertex coordinates for a quad that covers the screen exactly
313 extern const float r_screenvertex3f[12];
314 const float r_screenvertex3f[12] =
315 {
316         0, 0, 0,
317         1, 0, 0,
318         1, 1, 0,
319         0, 1, 0
320 };
321
322 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
323 {
324         int i;
325         for (i = 0;i < verts;i++)
326         {
327                 out[0] = in[0] * r;
328                 out[1] = in[1] * g;
329                 out[2] = in[2] * b;
330                 out[3] = in[3];
331                 in += 4;
332                 out += 4;
333         }
334 }
335
336 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
337 {
338         int i;
339         for (i = 0;i < verts;i++)
340         {
341                 out[0] = r;
342                 out[1] = g;
343                 out[2] = b;
344                 out[3] = a;
345                 out += 4;
346         }
347 }
348
349 // FIXME: move this to client?
350 void FOG_clear(void)
351 {
352         if (gamemode == GAME_NEHAHRA)
353         {
354                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
355                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
356                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
357                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
358                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
359         }
360         r_refdef.fog_density = 0;
361         r_refdef.fog_red = 0;
362         r_refdef.fog_green = 0;
363         r_refdef.fog_blue = 0;
364         r_refdef.fog_alpha = 1;
365         r_refdef.fog_start = 0;
366         r_refdef.fog_end = 16384;
367         r_refdef.fog_height = 1<<30;
368         r_refdef.fog_fadedepth = 128;
369         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
370 }
371
372 static void R_BuildBlankTextures(void)
373 {
374         unsigned char data[4];
375         data[2] = 128; // normal X
376         data[1] = 128; // normal Y
377         data[0] = 255; // normal Z
378         data[3] = 255; // height
379         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
380         data[0] = 255;
381         data[1] = 255;
382         data[2] = 255;
383         data[3] = 255;
384         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
385         data[0] = 128;
386         data[1] = 128;
387         data[2] = 128;
388         data[3] = 255;
389         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
390         data[0] = 0;
391         data[1] = 0;
392         data[2] = 0;
393         data[3] = 255;
394         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
395 }
396
397 static void R_BuildNoTexture(void)
398 {
399         int x, y;
400         unsigned char pix[16][16][4];
401         // this makes a light grey/dark grey checkerboard texture
402         for (y = 0;y < 16;y++)
403         {
404                 for (x = 0;x < 16;x++)
405                 {
406                         if ((y < 8) ^ (x < 8))
407                         {
408                                 pix[y][x][0] = 128;
409                                 pix[y][x][1] = 128;
410                                 pix[y][x][2] = 128;
411                                 pix[y][x][3] = 255;
412                         }
413                         else
414                         {
415                                 pix[y][x][0] = 64;
416                                 pix[y][x][1] = 64;
417                                 pix[y][x][2] = 64;
418                                 pix[y][x][3] = 255;
419                         }
420                 }
421         }
422         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
423 }
424
425 static void R_BuildWhiteCube(void)
426 {
427         unsigned char data[6*1*1*4];
428         memset(data, 255, sizeof(data));
429         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
430 }
431
432 static void R_BuildNormalizationCube(void)
433 {
434         int x, y, side;
435         vec3_t v;
436         vec_t s, t, intensity;
437 #define NORMSIZE 64
438         unsigned char *data;
439         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
440         for (side = 0;side < 6;side++)
441         {
442                 for (y = 0;y < NORMSIZE;y++)
443                 {
444                         for (x = 0;x < NORMSIZE;x++)
445                         {
446                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
447                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
448                                 switch(side)
449                                 {
450                                 default:
451                                 case 0:
452                                         v[0] = 1;
453                                         v[1] = -t;
454                                         v[2] = -s;
455                                         break;
456                                 case 1:
457                                         v[0] = -1;
458                                         v[1] = -t;
459                                         v[2] = s;
460                                         break;
461                                 case 2:
462                                         v[0] = s;
463                                         v[1] = 1;
464                                         v[2] = t;
465                                         break;
466                                 case 3:
467                                         v[0] = s;
468                                         v[1] = -1;
469                                         v[2] = -t;
470                                         break;
471                                 case 4:
472                                         v[0] = s;
473                                         v[1] = -t;
474                                         v[2] = 1;
475                                         break;
476                                 case 5:
477                                         v[0] = -s;
478                                         v[1] = -t;
479                                         v[2] = -1;
480                                         break;
481                                 }
482                                 intensity = 127.0f / sqrt(DotProduct(v, v));
483                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
484                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
485                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
486                                 data[((side*64+y)*64+x)*4+3] = 255;
487                         }
488                 }
489         }
490         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
491         Mem_Free(data);
492 }
493
494 static void R_BuildFogTexture(void)
495 {
496         int x, b;
497 #define FOGWIDTH 256
498         unsigned char data1[FOGWIDTH][4];
499         //unsigned char data2[FOGWIDTH][4];
500         double d, r, alpha;
501
502         r_refdef.fogmasktable_start = r_refdef.fog_start;
503         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
504         r_refdef.fogmasktable_range = r_refdef.fogrange;
505         r_refdef.fogmasktable_density = r_refdef.fog_density;
506
507         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
508         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
509         {
510                 d = (x * r - r_refdef.fogmasktable_start);
511                 if(developer_extra.integer)
512                         Con_DPrintf("%f ", d);
513                 d = max(0, d);
514                 if (r_fog_exp2.integer)
515                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
516                 else
517                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
518                 if(developer_extra.integer)
519                         Con_DPrintf(" : %f ", alpha);
520                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
521                 if(developer_extra.integer)
522                         Con_DPrintf(" = %f\n", alpha);
523                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
524         }
525
526         for (x = 0;x < FOGWIDTH;x++)
527         {
528                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
529                 data1[x][0] = b;
530                 data1[x][1] = b;
531                 data1[x][2] = b;
532                 data1[x][3] = 255;
533                 //data2[x][0] = 255 - b;
534                 //data2[x][1] = 255 - b;
535                 //data2[x][2] = 255 - b;
536                 //data2[x][3] = 255;
537         }
538         if (r_texture_fogattenuation)
539         {
540                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
541                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
542         }
543         else
544         {
545                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
546                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
547         }
548 }
549
550 static void R_BuildFogHeightTexture(void)
551 {
552         unsigned char *inpixels;
553         int size;
554         int x;
555         int y;
556         int j;
557         float c[4];
558         float f;
559         inpixels = NULL;
560         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
561         if (r_refdef.fogheighttexturename[0])
562                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
563         if (!inpixels)
564         {
565                 r_refdef.fog_height_tablesize = 0;
566                 if (r_texture_fogheighttexture)
567                         R_FreeTexture(r_texture_fogheighttexture);
568                 r_texture_fogheighttexture = NULL;
569                 if (r_refdef.fog_height_table2d)
570                         Mem_Free(r_refdef.fog_height_table2d);
571                 r_refdef.fog_height_table2d = NULL;
572                 if (r_refdef.fog_height_table1d)
573                         Mem_Free(r_refdef.fog_height_table1d);
574                 r_refdef.fog_height_table1d = NULL;
575                 return;
576         }
577         size = image_width;
578         r_refdef.fog_height_tablesize = size;
579         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
580         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
581         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
582         Mem_Free(inpixels);
583         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
584         // average fog color table accounting for every fog layer between a point
585         // and the camera.  (Note: attenuation is handled separately!)
586         for (y = 0;y < size;y++)
587         {
588                 for (x = 0;x < size;x++)
589                 {
590                         Vector4Clear(c);
591                         f = 0;
592                         if (x < y)
593                         {
594                                 for (j = x;j <= y;j++)
595                                 {
596                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
597                                         f++;
598                                 }
599                         }
600                         else
601                         {
602                                 for (j = x;j >= y;j--)
603                                 {
604                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
605                                         f++;
606                                 }
607                         }
608                         f = 1.0f / f;
609                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
610                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
611                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
612                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
613                 }
614         }
615         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
616 }
617
618 #define LUT_SLICE_SIZE 64
619 #define LUT_FACTOR (256 / LUT_SLICE_SIZE)
620 #define LUT_SLICES_X 8
621 #define LUT_SLICES_Y 8
622 #define LUT_WIDTH (LUT_SLICE_SIZE * LUT_SLICES_X)
623 #define LUT_HEIGHT (LUT_SLICE_SIZE * LUT_SLICES_Y)
624
625 static void R_BuildDefaultLUT(void)
626 {
627         unsigned char *p, *data;
628         int x, y;
629         data = (unsigned char *)Mem_Alloc(r_main_mempool, LUT_WIDTH * LUT_HEIGHT * 4);
630         p = data;
631         for (y = 0; y < LUT_HEIGHT; ++y)
632                 for (x = 0; x < LUT_WIDTH; ++x)
633                 {
634                         p[3] = 255;
635                         p[2] = (x % LUT_SLICE_SIZE) * LUT_FACTOR;
636                         p[1] = (y % LUT_SLICE_SIZE) * LUT_FACTOR;
637                         p[0] = ((y / LUT_SLICE_SIZE) * LUT_SLICES_X + x / LUT_SLICE_SIZE) * LUT_FACTOR;
638                         p += 4;
639                 }
640         r_texture_lut_default = R_LoadTexture2D(r_main_texturepool, "lutdefault", LUT_WIDTH, LUT_HEIGHT, data, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
641         r_texture_lut = r_texture_lut_default;
642 }
643
644 //=======================================================================================================================================================
645
646 static const char *builtinshaderstrings[] =
647 {
648 #include "shader_glsl.h"
649 0
650 };
651
652 //=======================================================================================================================================================
653
654 typedef struct shaderpermutationinfo_s
655 {
656         const char *pretext;
657         const char *name;
658 }
659 shaderpermutationinfo_t;
660
661 typedef struct shadermodeinfo_s
662 {
663         const char *sourcebasename;
664         const char *extension;
665         const char **builtinshaderstrings;
666         const char *pretext;
667         const char *name;
668         char *filename;
669         char *builtinstring;
670         int builtincrc;
671 }
672 shadermodeinfo_t;
673
674 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
675 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
676 {
677         {"#define USEDIFFUSE\n", " diffuse"},
678         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
679         {"#define USEVIEWTINT\n", " viewtint"},
680         {"#define USECOLORMAPPING\n", " colormapping"},
681         {"#define USESATURATION\n", " saturation"},
682         {"#define USEFOGINSIDE\n", " foginside"},
683         {"#define USEFOGOUTSIDE\n", " fogoutside"},
684         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
685         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
686         {"#define USEGAMMARAMPS\n", " gammaramps"},
687         {"#define USECUBEFILTER\n", " cubefilter"},
688         {"#define USEGLOW\n", " glow"},
689         {"#define USEBLOOM\n", " bloom"},
690         {"#define USESPECULAR\n", " specular"},
691         {"#define USEPOSTPROCESSING\n", " postprocessing"},
692         {"#define USEREFLECTION\n", " reflection"},
693         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
694         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
695         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
696         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
697         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
698         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
699         {"#define USEALPHAKILL\n", " alphakill"},
700         {"#define USEREFLECTCUBE\n", " reflectcube"},
701         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
702         {"#define USEBOUNCEGRID\n", " bouncegrid"},
703         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
704         {"#define USETRIPPY\n", " trippy"},
705         {"#define USEDEPTHRGB\n", " depthrgb"},
706         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
707         {"#define USESKELETAL\n", " skeletal"},
708         {"#define USEOCCLUDE\n", " occlude"}
709 };
710
711 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
712 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
713 {
714         // SHADERLANGUAGE_GLSL
715         {
716                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
717                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
718                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
719                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
720                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
721                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
722                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
723                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
724                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
725                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
726                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
727                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
728                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
729                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
730                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
731                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
732                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
733         },
734 };
735
736 struct r_glsl_permutation_s;
737 typedef struct r_glsl_permutation_s
738 {
739         /// hash lookup data
740         struct r_glsl_permutation_s *hashnext;
741         unsigned int mode;
742         dpuint64 permutation;
743
744         /// indicates if we have tried compiling this permutation already
745         qboolean compiled;
746         /// 0 if compilation failed
747         int program;
748         // texture units assigned to each detected uniform
749         int tex_Texture_First;
750         int tex_Texture_Second;
751         int tex_Texture_GammaRamps;
752         int tex_Texture_Normal;
753         int tex_Texture_Color;
754         int tex_Texture_Gloss;
755         int tex_Texture_Glow;
756         int tex_Texture_SecondaryNormal;
757         int tex_Texture_SecondaryColor;
758         int tex_Texture_SecondaryGloss;
759         int tex_Texture_SecondaryGlow;
760         int tex_Texture_Pants;
761         int tex_Texture_Shirt;
762         int tex_Texture_FogHeightTexture;
763         int tex_Texture_FogMask;
764         int tex_Texture_LightGrid;
765         int tex_Texture_Lightmap;
766         int tex_Texture_Deluxemap;
767         int tex_Texture_Attenuation;
768         int tex_Texture_Cube;
769         int tex_Texture_Refraction;
770         int tex_Texture_Reflection;
771         int tex_Texture_ShadowMap2D;
772         int tex_Texture_CubeProjection;
773         int tex_Texture_ScreenNormalMap;
774         int tex_Texture_ScreenDiffuse;
775         int tex_Texture_ScreenSpecular;
776         int tex_Texture_ReflectMask;
777         int tex_Texture_ReflectCube;
778         int tex_Texture_BounceGrid;
779         int tex_Texture_LUT;
780         /// locations of detected uniforms in program object, or -1 if not found
781         int loc_Texture_First;
782         int loc_Texture_Second;
783         int loc_Texture_GammaRamps;
784         int loc_Texture_Normal;
785         int loc_Texture_Color;
786         int loc_Texture_Gloss;
787         int loc_Texture_Glow;
788         int loc_Texture_SecondaryNormal;
789         int loc_Texture_SecondaryColor;
790         int loc_Texture_SecondaryGloss;
791         int loc_Texture_SecondaryGlow;
792         int loc_Texture_Pants;
793         int loc_Texture_Shirt;
794         int loc_Texture_FogHeightTexture;
795         int loc_Texture_FogMask;
796         int loc_Texture_LightGrid;
797         int loc_Texture_Lightmap;
798         int loc_Texture_Deluxemap;
799         int loc_Texture_Attenuation;
800         int loc_Texture_Cube;
801         int loc_Texture_Refraction;
802         int loc_Texture_Reflection;
803         int loc_Texture_ShadowMap2D;
804         int loc_Texture_CubeProjection;
805         int loc_Texture_ScreenNormalMap;
806         int loc_Texture_ScreenDiffuse;
807         int loc_Texture_ScreenSpecular;
808         int loc_Texture_ReflectMask;
809         int loc_Texture_ReflectCube;
810         int loc_Texture_BounceGrid;
811         int loc_Texture_LUT;
812         int loc_Alpha;
813         int loc_BloomBlur_Parameters;
814         int loc_ClientTime;
815         int loc_Color_Ambient;
816         int loc_Color_Diffuse;
817         int loc_Color_Specular;
818         int loc_Color_Glow;
819         int loc_Color_Pants;
820         int loc_Color_Shirt;
821         int loc_DeferredColor_Ambient;
822         int loc_DeferredColor_Diffuse;
823         int loc_DeferredColor_Specular;
824         int loc_DeferredMod_Diffuse;
825         int loc_DeferredMod_Specular;
826         int loc_DistortScaleRefractReflect;
827         int loc_EyePosition;
828         int loc_FogColor;
829         int loc_FogHeightFade;
830         int loc_FogPlane;
831         int loc_FogPlaneViewDist;
832         int loc_FogRangeRecip;
833         int loc_LightColor;
834         int loc_LightDir;
835         int loc_LightGridMatrix;
836         int loc_LightGridNormalMatrix;
837         int loc_LightPosition;
838         int loc_OffsetMapping_ScaleSteps;
839         int loc_OffsetMapping_LodDistance;
840         int loc_OffsetMapping_Bias;
841         int loc_PixelSize;
842         int loc_ReflectColor;
843         int loc_ReflectFactor;
844         int loc_ReflectOffset;
845         int loc_RefractColor;
846         int loc_Saturation;
847         int loc_ScreenCenterRefractReflect;
848         int loc_ScreenScaleRefractReflect;
849         int loc_ScreenToDepth;
850         int loc_ShadowMap_Parameters;
851         int loc_ShadowMap_TextureScale;
852         int loc_SpecularPower;
853         int loc_Skeletal_Transform12;
854         int loc_UserVec1;
855         int loc_UserVec2;
856         int loc_UserVec3;
857         int loc_UserVec4;
858         int loc_ColorFringe;
859         int loc_ViewTintColor;
860         int loc_ViewToLight;
861         int loc_ModelToLight;
862         int loc_TexMatrix;
863         int loc_BackgroundTexMatrix;
864         int loc_ModelViewProjectionMatrix;
865         int loc_ModelViewMatrix;
866         int loc_PixelToScreenTexCoord;
867         int loc_ModelToReflectCube;
868         int loc_ShadowMapMatrix;
869         int loc_BloomColorSubtract;
870         int loc_NormalmapScrollBlend;
871         int loc_BounceGridMatrix;
872         int loc_BounceGridIntensity;
873         /// uniform block bindings
874         int ubibind_Skeletal_Transform12_UniformBlock;
875         /// uniform block indices
876         int ubiloc_Skeletal_Transform12_UniformBlock;
877 }
878 r_glsl_permutation_t;
879
880 #define SHADERPERMUTATION_HASHSIZE 256
881
882
883 // non-degradable "lightweight" shader parameters to keep the permutations simpler
884 // these can NOT degrade! only use for simple stuff
885 enum
886 {
887         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
888         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
889         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
890         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
891         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
892         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
893         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
894         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
895         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
896         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
897         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
898         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
899         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
900         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
901 };
902 #define SHADERSTATICPARMS_COUNT 14
903
904 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
905 static int shaderstaticparms_count = 0;
906
907 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
908 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
909
910 extern qboolean r_shadow_shadowmapsampler;
911 extern int r_shadow_shadowmappcf;
912 qboolean R_CompileShader_CheckStaticParms(void)
913 {
914         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
915         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
916         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
917
918         // detect all
919         if (r_glsl_saturation_redcompensate.integer)
920                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
921         if (r_glsl_vertextextureblend_usebothalphas.integer)
922                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
923         if (r_shadow_glossexact.integer)
924                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
925         if (r_glsl_postprocess.integer)
926         {
927                 if (r_glsl_postprocess_uservec1_enable.integer)
928                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
929                 if (r_glsl_postprocess_uservec2_enable.integer)
930                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
931                 if (r_glsl_postprocess_uservec3_enable.integer)
932                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
933                 if (r_glsl_postprocess_uservec4_enable.integer)
934                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
935         }
936         if (r_fxaa.integer)
937                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
938         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
939                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
940
941         if (r_shadow_shadowmapsampler)
942                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
943         if (r_shadow_shadowmappcf > 1)
944                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
945         else if (r_shadow_shadowmappcf)
946                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
947         if (r_celshading.integer)
948                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
949         if (r_celoutlines.integer)
950                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
951
952         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
953 }
954
955 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
956         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
957                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
958         else \
959                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
960 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
961 {
962         shaderstaticparms_count = 0;
963
964         // emit all
965         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
966         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
967         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
968         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
969         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
970         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
971         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
972         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
973         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
974         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
975         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
976         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
977         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
978         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
979 }
980
981 /// information about each possible shader permutation
982 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
983 /// currently selected permutation
984 r_glsl_permutation_t *r_glsl_permutation;
985 /// storage for permutations linked in the hash table
986 memexpandablearray_t r_glsl_permutationarray;
987
988 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
989 {
990         //unsigned int hashdepth = 0;
991         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
992         r_glsl_permutation_t *p;
993         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
994         {
995                 if (p->mode == mode && p->permutation == permutation)
996                 {
997                         //if (hashdepth > 10)
998                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
999                         return p;
1000                 }
1001                 //hashdepth++;
1002         }
1003         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
1004         p->mode = mode;
1005         p->permutation = permutation;
1006         p->hashnext = r_glsl_permutationhash[mode][hashindex];
1007         r_glsl_permutationhash[mode][hashindex] = p;
1008         //if (hashdepth > 10)
1009         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
1010         return p;
1011 }
1012
1013 static char *R_ShaderStrCat(const char **strings)
1014 {
1015         char *string, *s;
1016         const char **p = strings;
1017         const char *t;
1018         size_t len = 0;
1019         for (p = strings;(t = *p);p++)
1020                 len += strlen(t);
1021         len++;
1022         s = string = (char *)Mem_Alloc(r_main_mempool, len);
1023         len = 0;
1024         for (p = strings;(t = *p);p++)
1025         {
1026                 len = strlen(t);
1027                 memcpy(s, t, len);
1028                 s += len;
1029         }
1030         *s = 0;
1031         return string;
1032 }
1033
1034 static char *R_ShaderStrCat(const char **strings);
1035 static void R_InitShaderModeInfo(void)
1036 {
1037         int i, language;
1038         shadermodeinfo_t *modeinfo;
1039         // 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)
1040         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1041         {
1042                 for (i = 0; i < SHADERMODE_COUNT; i++)
1043                 {
1044                         char filename[MAX_QPATH];
1045                         modeinfo = &shadermodeinfo[language][i];
1046                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1047                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1048                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1049                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1050                 }
1051         }
1052 }
1053
1054 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1055 {
1056         char *shaderstring;
1057         // if the mode has no filename we have to return the builtin string
1058         if (builtinonly || !modeinfo->filename)
1059                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1060         // note that FS_LoadFile appends a 0 byte to make it a valid string
1061         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1062         if (shaderstring)
1063         {
1064                 if (printfromdisknotice)
1065                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1066                 return shaderstring;
1067         }
1068         // fall back to builtinstring
1069         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1070 }
1071
1072 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1073 {
1074         int i;
1075         int ubibind;
1076         int sampler;
1077         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1078         char *sourcestring;
1079         char permutationname[256];
1080         int vertstrings_count = 0;
1081         int geomstrings_count = 0;
1082         int fragstrings_count = 0;
1083         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1084         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1085         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1086
1087         if (p->compiled)
1088                 return;
1089         p->compiled = true;
1090         p->program = 0;
1091
1092         permutationname[0] = 0;
1093         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1094
1095         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1096
1097         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1098         if(vid.support.glshaderversion >= 140)
1099         {
1100                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1101                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1102                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1103                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1104                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1105                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1106         }
1107         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1108         else if(vid.support.glshaderversion >= 130)
1109         {
1110                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1111                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1112                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1113                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1114                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1115                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1116         }
1117         // if we can do #version 120, we should (this adds the invariant keyword)
1118         else if(vid.support.glshaderversion >= 120)
1119         {
1120                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1121                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1122                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1123                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1124                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1125                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1126         }
1127         // GLES also adds several things from GLSL120
1128         switch(vid.renderpath)
1129         {
1130         case RENDERPATH_GLES2:
1131                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1132                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1133                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1134                 break;
1135         default:
1136                 break;
1137         }
1138
1139         // the first pretext is which type of shader to compile as
1140         // (later these will all be bound together as a program object)
1141         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1142         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1143         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1144
1145         // the second pretext is the mode (for example a light source)
1146         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1147         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1148         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1149         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1150
1151         // now add all the permutation pretexts
1152         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1153         {
1154                 if (permutation & (1ll<<i))
1155                 {
1156                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1157                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1158                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1159                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1160                 }
1161                 else
1162                 {
1163                         // keep line numbers correct
1164                         vertstrings_list[vertstrings_count++] = "\n";
1165                         geomstrings_list[geomstrings_count++] = "\n";
1166                         fragstrings_list[fragstrings_count++] = "\n";
1167                 }
1168         }
1169
1170         // add static parms
1171         R_CompileShader_AddStaticParms(mode, permutation);
1172         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1173         vertstrings_count += shaderstaticparms_count;
1174         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1175         geomstrings_count += shaderstaticparms_count;
1176         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1177         fragstrings_count += shaderstaticparms_count;
1178
1179         // now append the shader text itself
1180         vertstrings_list[vertstrings_count++] = sourcestring;
1181         geomstrings_list[geomstrings_count++] = sourcestring;
1182         fragstrings_list[fragstrings_count++] = sourcestring;
1183
1184         // we don't currently use geometry shaders for anything, so just empty the list
1185         geomstrings_count = 0;
1186
1187         // compile the shader program
1188         if (vertstrings_count + geomstrings_count + fragstrings_count)
1189                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1190         if (p->program)
1191         {
1192                 CHECKGLERROR
1193                 qglUseProgram(p->program);CHECKGLERROR
1194                 // look up all the uniform variable names we care about, so we don't
1195                 // have to look them up every time we set them
1196
1197 #if 0
1198                 // debugging aid
1199                 {
1200                         GLint activeuniformindex = 0;
1201                         GLint numactiveuniforms = 0;
1202                         char uniformname[128];
1203                         GLsizei uniformnamelength = 0;
1204                         GLint uniformsize = 0;
1205                         GLenum uniformtype = 0;
1206                         memset(uniformname, 0, sizeof(uniformname));
1207                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1208                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1209                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1210                         {
1211                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1212                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1213                         }
1214                 }
1215 #endif
1216
1217                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1218                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1219                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1220                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1221                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1222                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1223                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1224                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1225                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1226                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1227                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1228                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1229                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1230                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1231                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1232                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1233                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1234                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1235                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1236                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1237                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1238                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1239                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1240                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1241                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1242                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1243                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1244                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1245                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1246                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1247                 p->loc_Texture_LUT                = qglGetUniformLocation(p->program, "Texture_LUT");
1248                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1249                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1250                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1251                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1252                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1253                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1254                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1255                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1256                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1257                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1258                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1259                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1260                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1261                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1262                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1263                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1264                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1265                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1266                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1267                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1268                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1269                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1270                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1271                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1272                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1273                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1274                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1275                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1276                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1277                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1278                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1279                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1280                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1281                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1282                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1283                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1284                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1285                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1286                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1287                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1288                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1289                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1290                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1291                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1292                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1293                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1294                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1295                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1296                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1297                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1298                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1299                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1300                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1301                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1302                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1303                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1304                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1305                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1306                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1307                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1308                 // initialize the samplers to refer to the texture units we use
1309                 p->tex_Texture_First = -1;
1310                 p->tex_Texture_Second = -1;
1311                 p->tex_Texture_GammaRamps = -1;
1312                 p->tex_Texture_Normal = -1;
1313                 p->tex_Texture_Color = -1;
1314                 p->tex_Texture_Gloss = -1;
1315                 p->tex_Texture_Glow = -1;
1316                 p->tex_Texture_SecondaryNormal = -1;
1317                 p->tex_Texture_SecondaryColor = -1;
1318                 p->tex_Texture_SecondaryGloss = -1;
1319                 p->tex_Texture_SecondaryGlow = -1;
1320                 p->tex_Texture_Pants = -1;
1321                 p->tex_Texture_Shirt = -1;
1322                 p->tex_Texture_FogHeightTexture = -1;
1323                 p->tex_Texture_FogMask = -1;
1324                 p->tex_Texture_LightGrid = -1;
1325                 p->tex_Texture_Lightmap = -1;
1326                 p->tex_Texture_Deluxemap = -1;
1327                 p->tex_Texture_Attenuation = -1;
1328                 p->tex_Texture_Cube = -1;
1329                 p->tex_Texture_Refraction = -1;
1330                 p->tex_Texture_Reflection = -1;
1331                 p->tex_Texture_ShadowMap2D = -1;
1332                 p->tex_Texture_CubeProjection = -1;
1333                 p->tex_Texture_ScreenNormalMap = -1;
1334                 p->tex_Texture_ScreenDiffuse = -1;
1335                 p->tex_Texture_ScreenSpecular = -1;
1336                 p->tex_Texture_ReflectMask = -1;
1337                 p->tex_Texture_ReflectCube = -1;
1338                 p->tex_Texture_BounceGrid = -1;
1339                 p->tex_Texture_LUT = -1;
1340                 // bind the texture samplers in use
1341                 sampler = 0;
1342                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1343                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1344                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1345                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1346                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1347                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1348                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1349                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1350                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1351                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1352                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1353                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1354                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1355                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1356                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1357                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1358                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1359                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1360                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1361                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1362                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1363                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1364                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1365                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1366                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1367                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1368                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1369                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1370                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1371                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1372                 if (p->loc_Texture_LUT             >= 0) {p->tex_Texture_LUT              = sampler;qglUniform1i(p->loc_Texture_LUT             , sampler);sampler++;}
1373                 // get the uniform block indices so we can bind them
1374                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1375 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1376                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1377 #endif
1378                 // clear the uniform block bindings
1379                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1380                 // bind the uniform blocks in use
1381                 ubibind = 0;
1382 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1383                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1384 #endif
1385                 // we're done compiling and setting up the shader, at least until it is used
1386                 CHECKGLERROR
1387                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1388         }
1389         else
1390                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1391
1392         // free the strings
1393         if (sourcestring)
1394                 Mem_Free(sourcestring);
1395 }
1396
1397 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1398 {
1399         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1400         if (r_glsl_permutation != perm)
1401         {
1402                 r_glsl_permutation = perm;
1403                 if (!r_glsl_permutation->program)
1404                 {
1405                         if (!r_glsl_permutation->compiled)
1406                         {
1407                                 Con_DPrintf("Compiling shader mode %u permutation %llx\n", mode, permutation);
1408                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1409                         }
1410                         if (!r_glsl_permutation->program)
1411                         {
1412                                 // remove features until we find a valid permutation
1413                                 int i;
1414                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1415                                 {
1416                                         // reduce i more quickly whenever it would not remove any bits
1417                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1418                                         if (!(permutation & j))
1419                                                 continue;
1420                                         permutation -= j;
1421                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1422                                         if (!r_glsl_permutation->compiled)
1423                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1424                                         if (r_glsl_permutation->program)
1425                                                 break;
1426                                 }
1427                                 if (i >= SHADERPERMUTATION_COUNT)
1428                                 {
1429                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1430                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1431                                         qglUseProgram(0);CHECKGLERROR
1432                                         return; // no bit left to clear, entire mode is broken
1433                                 }
1434                         }
1435                 }
1436                 CHECKGLERROR
1437                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1438         }
1439         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1440         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1441         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1442         CHECKGLERROR
1443 }
1444
1445 void R_GLSL_Restart_f(cmd_state_t *cmd)
1446 {
1447         unsigned int i, limit;
1448         switch(vid.renderpath)
1449         {
1450         case RENDERPATH_GL32:
1451         case RENDERPATH_GLES2:
1452                 {
1453                         r_glsl_permutation_t *p;
1454                         r_glsl_permutation = NULL;
1455                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1456                         for (i = 0;i < limit;i++)
1457                         {
1458                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1459                                 {
1460                                         GL_Backend_FreeProgram(p->program);
1461                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1462                                 }
1463                         }
1464                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1465                 }
1466                 break;
1467         }
1468 }
1469
1470 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1471 {
1472         int i, language, mode, dupe;
1473         char *text;
1474         shadermodeinfo_t *modeinfo;
1475         qfile_t *file;
1476
1477         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1478         {
1479                 modeinfo = shadermodeinfo[language];
1480                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1481                 {
1482                         // don't dump the same file multiple times (most or all shaders come from the same file)
1483                         for (dupe = mode - 1;dupe >= 0;dupe--)
1484                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1485                                         break;
1486                         if (dupe >= 0)
1487                                 continue;
1488                         text = modeinfo[mode].builtinstring;
1489                         if (!text)
1490                                 continue;
1491                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1492                         if (file)
1493                         {
1494                                 FS_Print(file, "/* The engine may define the following macros:\n");
1495                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1496                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1497                                         FS_Print(file, modeinfo[i].pretext);
1498                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1499                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1500                                 FS_Print(file, "*/\n");
1501                                 FS_Print(file, text);
1502                                 FS_Close(file);
1503                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1504                         }
1505                         else
1506                                 Con_Errorf("failed to write to %s\n", modeinfo[mode].filename);
1507                 }
1508         }
1509 }
1510
1511 void R_SetupShader_Generic(rtexture_t *t, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1512 {
1513         dpuint64 permutation = 0;
1514         if (r_trippy.integer && !notrippy)
1515                 permutation |= SHADERPERMUTATION_TRIPPY;
1516         permutation |= SHADERPERMUTATION_VIEWTINT;
1517         if (t)
1518                 permutation |= SHADERPERMUTATION_DIFFUSE;
1519         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1520                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1521         if (suppresstexalpha)
1522                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1523         if (vid.allowalphatocoverage)
1524                 GL_AlphaToCoverage(false);
1525         switch (vid.renderpath)
1526         {
1527         case RENDERPATH_GL32:
1528         case RENDERPATH_GLES2:
1529                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1530                 if (r_glsl_permutation->tex_Texture_First >= 0)
1531                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1532                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1533                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1534                 if (r_glsl_permutation->tex_Texture_LUT >= 0)
1535                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LUT, r_texture_lut);
1536                 break;
1537         }
1538 }
1539
1540 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1541 {
1542         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1543 }
1544
1545 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1546 {
1547         dpuint64 permutation = 0;
1548         if (r_trippy.integer && !notrippy)
1549                 permutation |= SHADERPERMUTATION_TRIPPY;
1550         if (depthrgb)
1551                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1552         if (skeletal)
1553                 permutation |= SHADERPERMUTATION_SKELETAL;
1554
1555         if (vid.allowalphatocoverage)
1556                 GL_AlphaToCoverage(false);
1557         switch (vid.renderpath)
1558         {
1559         case RENDERPATH_GL32:
1560         case RENDERPATH_GLES2:
1561                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1562 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1563                 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);
1564 #endif
1565                 break;
1566         }
1567 }
1568
1569 #define BLENDFUNC_ALLOWS_COLORMOD      1
1570 #define BLENDFUNC_ALLOWS_FOG           2
1571 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1572 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1573 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1574 static int R_BlendFuncFlags(int src, int dst)
1575 {
1576         int r = 0;
1577
1578         // a blendfunc allows colormod if:
1579         // a) it can never keep the destination pixel invariant, or
1580         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1581         // this is to prevent unintended side effects from colormod
1582
1583         // a blendfunc allows fog if:
1584         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1585         // this is to prevent unintended side effects from fog
1586
1587         // these checks are the output of fogeval.pl
1588
1589         r |= BLENDFUNC_ALLOWS_COLORMOD;
1590         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1591         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1592         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1593         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1594         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1595         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1596         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1597         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1598         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1599         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1600         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1601         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1602         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1603         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1604         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1605         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1606         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1607         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1608         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1609         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1610         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1611
1612         return r;
1613 }
1614
1615 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)
1616 {
1617         // select a permutation of the lighting shader appropriate to this
1618         // combination of texture, entity, light source, and fogging, only use the
1619         // minimum features necessary to avoid wasting rendering time in the
1620         // fragment shader on features that are not being used
1621         dpuint64 permutation = 0;
1622         unsigned int mode = 0;
1623         int blendfuncflags;
1624         texture_t *t = rsurface.texture;
1625         float m16f[16];
1626         matrix4x4_t tempmatrix;
1627         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1628         if (r_trippy.integer && !notrippy)
1629                 permutation |= SHADERPERMUTATION_TRIPPY;
1630         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1631                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1632         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1633                 permutation |= SHADERPERMUTATION_OCCLUDE;
1634         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1635                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1636         if (rsurfacepass == RSURFPASS_BACKGROUND)
1637         {
1638                 // distorted background
1639                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1640                 {
1641                         mode = SHADERMODE_WATER;
1642                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1643                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1644                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1645                         {
1646                                 // this is the right thing to do for wateralpha
1647                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1648                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1649                         }
1650                         else
1651                         {
1652                                 // this is the right thing to do for entity alpha
1653                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1654                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1655                         }
1656                 }
1657                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1658                 {
1659                         mode = SHADERMODE_REFRACTION;
1660                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1661                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1662                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1663                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1664                 }
1665                 else
1666                 {
1667                         mode = SHADERMODE_GENERIC;
1668                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1669                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1670                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1671                 }
1672                 if (vid.allowalphatocoverage)
1673                         GL_AlphaToCoverage(false);
1674         }
1675         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1676         {
1677                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1678                 {
1679                         switch(t->offsetmapping)
1680                         {
1681                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1682                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1683                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1684                         case OFFSETMAPPING_OFF: break;
1685                         }
1686                 }
1687                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1688                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1689                 // normalmap (deferred prepass), may use alpha test on diffuse
1690                 mode = SHADERMODE_DEFERREDGEOMETRY;
1691                 GL_BlendFunc(GL_ONE, GL_ZERO);
1692                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1693                 if (vid.allowalphatocoverage)
1694                         GL_AlphaToCoverage(false);
1695         }
1696         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1697         {
1698                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1699                 {
1700                         switch(t->offsetmapping)
1701                         {
1702                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1703                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1704                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1705                         case OFFSETMAPPING_OFF: break;
1706                         }
1707                 }
1708                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1709                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1710                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1711                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1712                 // light source
1713                 mode = SHADERMODE_LIGHTSOURCE;
1714                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1715                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1716                 if (VectorLength2(rtlightdiffuse) > 0)
1717                         permutation |= SHADERPERMUTATION_DIFFUSE;
1718                 if (VectorLength2(rtlightspecular) > 0)
1719                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1720                 if (r_refdef.fogenabled)
1721                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1722                 if (t->colormapping)
1723                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1724                 if (r_shadow_usingshadowmap2d)
1725                 {
1726                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1727                         if(r_shadow_shadowmapvsdct)
1728                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1729
1730                         if (r_shadow_shadowmap2ddepthbuffer)
1731                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1732                 }
1733                 if (t->reflectmasktexture)
1734                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1735                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1736                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1737                 if (vid.allowalphatocoverage)
1738                         GL_AlphaToCoverage(false);
1739         }
1740         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1741         {
1742                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1743                 {
1744                         switch(t->offsetmapping)
1745                         {
1746                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1747                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1748                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1749                         case OFFSETMAPPING_OFF: break;
1750                         }
1751                 }
1752                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1753                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1754                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1755                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1756                 // directional model lighting
1757                 mode = SHADERMODE_LIGHTGRID;
1758                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1759                         permutation |= SHADERPERMUTATION_GLOW;
1760                 permutation |= SHADERPERMUTATION_DIFFUSE;
1761                 if (t->glosstexture || t->backgroundglosstexture)
1762                         permutation |= SHADERPERMUTATION_SPECULAR;
1763                 if (r_refdef.fogenabled)
1764                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1765                 if (t->colormapping)
1766                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1767                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1768                 {
1769                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1770                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1771
1772                         if (r_shadow_shadowmap2ddepthbuffer)
1773                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1774                 }
1775                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1776                         permutation |= SHADERPERMUTATION_REFLECTION;
1777                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1778                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1779                 if (t->reflectmasktexture)
1780                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1781                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1782                 {
1783                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1784                         if (r_shadow_bouncegrid_state.directional)
1785                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1786                 }
1787                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1788                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1789                 // when using alphatocoverage, we don't need alphakill
1790                 if (vid.allowalphatocoverage)
1791                 {
1792                         if (r_transparent_alphatocoverage.integer)
1793                         {
1794                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1795                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1796                         }
1797                         else
1798                                 GL_AlphaToCoverage(false);
1799                 }
1800         }
1801         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1802         {
1803                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1804                 {
1805                         switch(t->offsetmapping)
1806                         {
1807                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1808                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1809                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1810                         case OFFSETMAPPING_OFF: break;
1811                         }
1812                 }
1813                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1814                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1815                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1816                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1817                 // directional model lighting
1818                 mode = SHADERMODE_LIGHTDIRECTION;
1819                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1820                         permutation |= SHADERPERMUTATION_GLOW;
1821                 if (VectorLength2(t->render_modellight_diffuse))
1822                         permutation |= SHADERPERMUTATION_DIFFUSE;
1823                 if (VectorLength2(t->render_modellight_specular) > 0)
1824                         permutation |= SHADERPERMUTATION_SPECULAR;
1825                 if (r_refdef.fogenabled)
1826                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1827                 if (t->colormapping)
1828                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1829                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1830                 {
1831                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1832                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1833
1834                         if (r_shadow_shadowmap2ddepthbuffer)
1835                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1836                 }
1837                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1838                         permutation |= SHADERPERMUTATION_REFLECTION;
1839                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1840                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1841                 if (t->reflectmasktexture)
1842                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1843                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1844                 {
1845                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1846                         if (r_shadow_bouncegrid_state.directional)
1847                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1848                 }
1849                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1850                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1851                 // when using alphatocoverage, we don't need alphakill
1852                 if (vid.allowalphatocoverage)
1853                 {
1854                         if (r_transparent_alphatocoverage.integer)
1855                         {
1856                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1857                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1858                         }
1859                         else
1860                                 GL_AlphaToCoverage(false);
1861                 }
1862         }
1863         else
1864         {
1865                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1866                 {
1867                         switch(t->offsetmapping)
1868                         {
1869                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1870                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1871                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1872                         case OFFSETMAPPING_OFF: break;
1873                         }
1874                 }
1875                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1876                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1877                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1878                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1879                 // lightmapped wall
1880                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1881                         permutation |= SHADERPERMUTATION_GLOW;
1882                 if (r_refdef.fogenabled)
1883                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1884                 if (t->colormapping)
1885                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1886                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1887                 {
1888                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1889                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1890
1891                         if (r_shadow_shadowmap2ddepthbuffer)
1892                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1893                 }
1894                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1895                         permutation |= SHADERPERMUTATION_REFLECTION;
1896                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1897                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1898                 if (t->reflectmasktexture)
1899                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1900                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1901                 {
1902                         // deluxemapping (light direction texture)
1903                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1904                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1905                         else
1906                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1907                         permutation |= SHADERPERMUTATION_DIFFUSE;
1908                         if (VectorLength2(t->render_lightmap_specular) > 0)
1909                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1910                 }
1911                 else if (r_glsl_deluxemapping.integer >= 2)
1912                 {
1913                         // fake deluxemapping (uniform light direction in tangentspace)
1914                         if (rsurface.uselightmaptexture)
1915                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1916                         else
1917                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1918                         permutation |= SHADERPERMUTATION_DIFFUSE;
1919                         if (VectorLength2(t->render_lightmap_specular) > 0)
1920                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1921                 }
1922                 else if (rsurface.uselightmaptexture)
1923                 {
1924                         // ordinary lightmapping (q1bsp, q3bsp)
1925                         mode = SHADERMODE_LIGHTMAP;
1926                 }
1927                 else
1928                 {
1929                         // ordinary vertex coloring (q3bsp)
1930                         mode = SHADERMODE_VERTEXCOLOR;
1931                 }
1932                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1933                 {
1934                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1935                         if (r_shadow_bouncegrid_state.directional)
1936                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1937                 }
1938                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1939                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1940                 // when using alphatocoverage, we don't need alphakill
1941                 if (vid.allowalphatocoverage)
1942                 {
1943                         if (r_transparent_alphatocoverage.integer)
1944                         {
1945                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1946                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1947                         }
1948                         else
1949                                 GL_AlphaToCoverage(false);
1950                 }
1951         }
1952         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1953                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1954         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1955                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1956         switch(vid.renderpath)
1957         {
1958         case RENDERPATH_GL32:
1959         case RENDERPATH_GLES2:
1960                 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);
1961                 RSurf_UploadBuffersForBatch();
1962                 // this has to be after RSurf_PrepareVerticesForBatch
1963                 if (rsurface.batchskeletaltransform3x4buffer)
1964                         permutation |= SHADERPERMUTATION_SKELETAL;
1965                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1966 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1967                 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);
1968 #endif
1969                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1970                 if (mode == SHADERMODE_LIGHTSOURCE)
1971                 {
1972                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1973                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1974                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1975                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1976                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1977                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1978         
1979                         // additive passes are only darkened by fog, not tinted
1980                         if (r_glsl_permutation->loc_FogColor >= 0)
1981                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1982                         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);
1983                 }
1984                 else
1985                 {
1986                         if (mode == SHADERMODE_FLATCOLOR)
1987                         {
1988                                 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]);
1989                         }
1990                         else if (mode == SHADERMODE_LIGHTGRID)
1991                         {
1992                                 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]);
1993                                 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]);
1994                                 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]);
1995                                 // other LightGrid uniforms handled below
1996                         }
1997                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1998                         {
1999                                 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]);
2000                                 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]);
2001                                 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]);
2002                                 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]);
2003                                 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]);
2004                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
2005                                 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]);
2006                         }
2007                         else
2008                         {
2009                                 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]);
2010                                 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]);
2011                                 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]);
2012                                 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]);
2013                                 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]);
2014                         }
2015                         // additive passes are only darkened by fog, not tinted
2016                         if (r_glsl_permutation->loc_FogColor >= 0)
2017                         {
2018                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
2019                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
2020                                 else
2021                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
2022                         }
2023                         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);
2024                         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]);
2025                         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]);
2026                         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);
2027                         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);
2028                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
2029                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
2030                         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);
2031                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
2032                 }
2033                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
2034                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
2035                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
2036                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
2037                 {
2038                         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]);
2039                         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]);
2040                 }
2041                 else
2042                 {
2043                         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]);
2044                         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]);
2045                 }
2046
2047                 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]);
2048                 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));
2049                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2050                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2051                 {
2052                         if (t->pantstexture)
2053                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2054                         else
2055                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2056                 }
2057                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2058                 {
2059                         if (t->shirttexture)
2060                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2061                         else
2062                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2063                 }
2064                 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]);
2065                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2066                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2067                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2068                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2069                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2070                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2071                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2072                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2073                         );
2074                 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);
2075                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2076                 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]);
2077                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2078                 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);}
2079                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2080                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2081                 {
2082                         float m9f[9];
2083                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2084                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2085                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2086                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2087                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2088                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2089                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2090                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2091                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2092                 }
2093
2094                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2095                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2096                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2097                 if (r_glsl_permutation->tex_Texture_LUT             >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LUT              , r_texture_lut                                       );
2098                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2099                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2100                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2101                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2102                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2103                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2104                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2105                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2106                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2107                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2108                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2109                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2110                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2111                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2112                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2113                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2114                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2115                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2116                 {
2117                         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);
2118                         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);
2119                         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);
2120                 }
2121                 else
2122                 {
2123                         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);
2124                 }
2125                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2126                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2127                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2128                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2129                 {
2130                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2131                         if (rsurface.rtlight)
2132                         {
2133                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2134                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2135                         }
2136                 }
2137                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2138                 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);
2139                 CHECKGLERROR
2140                 break;
2141         }
2142 }
2143
2144 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2145 {
2146         // select a permutation of the lighting shader appropriate to this
2147         // combination of texture, entity, light source, and fogging, only use the
2148         // minimum features necessary to avoid wasting rendering time in the
2149         // fragment shader on features that are not being used
2150         dpuint64 permutation = 0;
2151         unsigned int mode = 0;
2152         const float *lightcolorbase = rtlight->currentcolor;
2153         float ambientscale = rtlight->ambientscale;
2154         float diffusescale = rtlight->diffusescale;
2155         float specularscale = rtlight->specularscale;
2156         // this is the location of the light in view space
2157         vec3_t viewlightorigin;
2158         // this transforms from view space (camera) to light space (cubemap)
2159         matrix4x4_t viewtolight;
2160         matrix4x4_t lighttoview;
2161         float viewtolight16f[16];
2162         // light source
2163         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2164         if (rtlight->currentcubemap != r_texture_whitecube)
2165                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2166         if (diffusescale > 0)
2167                 permutation |= SHADERPERMUTATION_DIFFUSE;
2168         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2169                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2170         if (r_shadow_usingshadowmap2d)
2171         {
2172                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2173                 if (r_shadow_shadowmapvsdct)
2174                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2175
2176                 if (r_shadow_shadowmap2ddepthbuffer)
2177                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2178         }
2179         if (vid.allowalphatocoverage)
2180                 GL_AlphaToCoverage(false);
2181         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2182         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2183         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2184         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2185         switch(vid.renderpath)
2186         {
2187         case RENDERPATH_GL32:
2188         case RENDERPATH_GLES2:
2189                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2190                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2191                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2192                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2193                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2194                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2195                 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]);
2196                 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]);
2197                 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);
2198                 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]);
2199                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2200
2201                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2202                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2203                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2204                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2205                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2206                 break;
2207         }
2208 }
2209
2210 #define SKINFRAME_HASH 1024
2211
2212 typedef struct
2213 {
2214         unsigned int loadsequence; // incremented each level change
2215         memexpandablearray_t array;
2216         skinframe_t *hash[SKINFRAME_HASH];
2217 }
2218 r_skinframe_t;
2219 r_skinframe_t r_skinframe;
2220
2221 void R_SkinFrame_PrepareForPurge(void)
2222 {
2223         r_skinframe.loadsequence++;
2224         // wrap it without hitting zero
2225         if (r_skinframe.loadsequence >= 200)
2226                 r_skinframe.loadsequence = 1;
2227 }
2228
2229 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2230 {
2231         if (!skinframe)
2232                 return;
2233         // mark the skinframe as used for the purging code
2234         skinframe->loadsequence = r_skinframe.loadsequence;
2235 }
2236
2237 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2238 {
2239         if (s == NULL)
2240                 return;
2241         if (s->merged == s->base)
2242                 s->merged = NULL;
2243         R_PurgeTexture(s->stain); s->stain = NULL;
2244         R_PurgeTexture(s->merged); s->merged = NULL;
2245         R_PurgeTexture(s->base); s->base = NULL;
2246         R_PurgeTexture(s->pants); s->pants = NULL;
2247         R_PurgeTexture(s->shirt); s->shirt = NULL;
2248         R_PurgeTexture(s->nmap); s->nmap = NULL;
2249         R_PurgeTexture(s->gloss); s->gloss = NULL;
2250         R_PurgeTexture(s->glow); s->glow = NULL;
2251         R_PurgeTexture(s->fog); s->fog = NULL;
2252         R_PurgeTexture(s->reflect); s->reflect = NULL;
2253         s->loadsequence = 0;
2254 }
2255
2256 void R_SkinFrame_Purge(void)
2257 {
2258         int i;
2259         skinframe_t *s;
2260         for (i = 0;i < SKINFRAME_HASH;i++)
2261         {
2262                 for (s = r_skinframe.hash[i];s;s = s->next)
2263                 {
2264                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2265                                 R_SkinFrame_PurgeSkinFrame(s);
2266                 }
2267         }
2268 }
2269
2270 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2271         skinframe_t *item;
2272         char basename[MAX_QPATH];
2273
2274         Image_StripImageExtension(name, basename, sizeof(basename));
2275
2276         if( last == NULL ) {
2277                 int hashindex;
2278                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2279                 item = r_skinframe.hash[hashindex];
2280         } else {
2281                 item = last->next;
2282         }
2283
2284         // linearly search through the hash bucket
2285         for( ; item ; item = item->next ) {
2286                 if( !strcmp( item->basename, basename ) ) {
2287                         return item;
2288                 }
2289         }
2290         return NULL;
2291 }
2292
2293 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2294 {
2295         skinframe_t *item;
2296         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2297         int hashindex;
2298         char basename[MAX_QPATH];
2299
2300         Image_StripImageExtension(name, basename, sizeof(basename));
2301
2302         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2303         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2304                 if (!strcmp(item->basename, basename) &&
2305                         item->textureflags == compareflags &&
2306                         item->comparewidth == comparewidth &&
2307                         item->compareheight == compareheight &&
2308                         item->comparecrc == comparecrc)
2309                         break;
2310
2311         if (!item)
2312         {
2313                 if (!add)
2314                         return NULL;
2315                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2316                 memset(item, 0, sizeof(*item));
2317                 strlcpy(item->basename, basename, sizeof(item->basename));
2318                 item->textureflags = compareflags;
2319                 item->comparewidth = comparewidth;
2320                 item->compareheight = compareheight;
2321                 item->comparecrc = comparecrc;
2322                 item->next = r_skinframe.hash[hashindex];
2323                 r_skinframe.hash[hashindex] = item;
2324         }
2325         else if (textureflags & TEXF_FORCE_RELOAD)
2326                 R_SkinFrame_PurgeSkinFrame(item);
2327
2328         R_SkinFrame_MarkUsed(item);
2329         return item;
2330 }
2331
2332 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2333         { \
2334                 unsigned long long avgcolor[5], wsum; \
2335                 int pix, comp, w; \
2336                 avgcolor[0] = 0; \
2337                 avgcolor[1] = 0; \
2338                 avgcolor[2] = 0; \
2339                 avgcolor[3] = 0; \
2340                 avgcolor[4] = 0; \
2341                 wsum = 0; \
2342                 for(pix = 0; pix < cnt; ++pix) \
2343                 { \
2344                         w = 0; \
2345                         for(comp = 0; comp < 3; ++comp) \
2346                                 w += getpixel; \
2347                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2348                         { \
2349                                 ++wsum; \
2350                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2351                                 w = getpixel; \
2352                                 for(comp = 0; comp < 3; ++comp) \
2353                                         avgcolor[comp] += getpixel * w; \
2354                                 avgcolor[3] += w; \
2355                         } \
2356                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2357                         avgcolor[4] += getpixel; \
2358                 } \
2359                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2360                         avgcolor[3] = 1; \
2361                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2362                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2363                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2364                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2365         }
2366
2367 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2368 {
2369         skinframe_t *skinframe;
2370
2371         if (cls.state == ca_dedicated)
2372                 return NULL;
2373
2374         // return an existing skinframe if already loaded
2375         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2376         if (skinframe && skinframe->base)
2377                 return skinframe;
2378
2379         // if the skinframe doesn't exist this will create it
2380         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2381 }
2382
2383 extern cvar_t gl_picmip;
2384 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2385 {
2386         int j;
2387         unsigned char *pixels;
2388         unsigned char *bumppixels;
2389         unsigned char *basepixels = NULL;
2390         int basepixels_width = 0;
2391         int basepixels_height = 0;
2392         rtexture_t *ddsbase = NULL;
2393         qboolean ddshasalpha = false;
2394         float ddsavgcolor[4];
2395         char basename[MAX_QPATH];
2396         int miplevel = R_PicmipForFlags(textureflags);
2397         int savemiplevel = miplevel;
2398         int mymiplevel;
2399         char vabuf[1024];
2400
2401         if (cls.state == ca_dedicated)
2402                 return NULL;
2403
2404         Image_StripImageExtension(name, basename, sizeof(basename));
2405
2406         // check for DDS texture file first
2407         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2408         {
2409                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2410                 if (basepixels == NULL && fallbacknotexture)
2411                         basepixels = Image_GenerateNoTexture();
2412                 if (basepixels == NULL)
2413                         return NULL;
2414         }
2415
2416         // FIXME handle miplevel
2417
2418         if (developer_loading.integer)
2419                 Con_Printf("loading skin \"%s\"\n", name);
2420
2421         // we've got some pixels to store, so really allocate this new texture now
2422         if (!skinframe)
2423                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2424         textureflags &= ~TEXF_FORCE_RELOAD;
2425         skinframe->stain = NULL;
2426         skinframe->merged = NULL;
2427         skinframe->base = NULL;
2428         skinframe->pants = NULL;
2429         skinframe->shirt = NULL;
2430         skinframe->nmap = NULL;
2431         skinframe->gloss = NULL;
2432         skinframe->glow = NULL;
2433         skinframe->fog = NULL;
2434         skinframe->reflect = NULL;
2435         skinframe->hasalpha = false;
2436         // we could store the q2animname here too
2437
2438         if (ddsbase)
2439         {
2440                 skinframe->base = ddsbase;
2441                 skinframe->hasalpha = ddshasalpha;
2442                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2443                 if (r_loadfog && skinframe->hasalpha)
2444                         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);
2445                 //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]);
2446         }
2447         else
2448         {
2449                 basepixels_width = image_width;
2450                 basepixels_height = image_height;
2451                 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);
2452                 if (textureflags & TEXF_ALPHA)
2453                 {
2454                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2455                         {
2456                                 if (basepixels[j] < 255)
2457                                 {
2458                                         skinframe->hasalpha = true;
2459                                         break;
2460                                 }
2461                         }
2462                         if (r_loadfog && skinframe->hasalpha)
2463                         {
2464                                 // has transparent pixels
2465                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2466                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2467                                 {
2468                                         pixels[j+0] = 255;
2469                                         pixels[j+1] = 255;
2470                                         pixels[j+2] = 255;
2471                                         pixels[j+3] = basepixels[j+3];
2472                                 }
2473                                 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);
2474                                 Mem_Free(pixels);
2475                         }
2476                 }
2477                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2478 #ifndef USE_GLES2
2479                 //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]);
2480                 if (r_savedds && skinframe->base)
2481                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2482                 if (r_savedds && skinframe->fog)
2483                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2484 #endif
2485         }
2486
2487         if (r_loaddds)
2488         {
2489                 mymiplevel = savemiplevel;
2490                 if (r_loadnormalmap)
2491                         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);
2492                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2493                 if (r_loadgloss)
2494                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2495                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2496                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2497                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2498         }
2499
2500         // _norm is the name used by tenebrae and has been adopted as standard
2501         if (r_loadnormalmap && skinframe->nmap == NULL)
2502         {
2503                 mymiplevel = savemiplevel;
2504                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2505                 {
2506                         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);
2507                         Mem_Free(pixels);
2508                         pixels = NULL;
2509                 }
2510                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2511                 {
2512                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2513                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2514                         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);
2515                         Mem_Free(pixels);
2516                         Mem_Free(bumppixels);
2517                 }
2518                 else if (r_shadow_bumpscale_basetexture.value > 0)
2519                 {
2520                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2521                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2522                         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);
2523                         Mem_Free(pixels);
2524                 }
2525 #ifndef USE_GLES2
2526                 if (r_savedds && skinframe->nmap)
2527                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2528 #endif
2529         }
2530
2531         // _luma is supported only for tenebrae compatibility
2532         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2533         // _glow is the preferred name
2534         mymiplevel = savemiplevel;
2535         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))))
2536         {
2537                 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);
2538 #ifndef USE_GLES2
2539                 if (r_savedds && skinframe->glow)
2540                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2541 #endif
2542                 Mem_Free(pixels);pixels = NULL;
2543         }
2544
2545         mymiplevel = savemiplevel;
2546         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2547         {
2548                 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);
2549 #ifndef USE_GLES2
2550                 if (r_savedds && skinframe->gloss)
2551                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2552 #endif
2553                 Mem_Free(pixels);
2554                 pixels = NULL;
2555         }
2556
2557         mymiplevel = savemiplevel;
2558         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2559         {
2560                 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);
2561 #ifndef USE_GLES2
2562                 if (r_savedds && skinframe->pants)
2563                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2564 #endif
2565                 Mem_Free(pixels);
2566                 pixels = NULL;
2567         }
2568
2569         mymiplevel = savemiplevel;
2570         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2571         {
2572                 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);
2573 #ifndef USE_GLES2
2574                 if (r_savedds && skinframe->shirt)
2575                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2576 #endif
2577                 Mem_Free(pixels);
2578                 pixels = NULL;
2579         }
2580
2581         mymiplevel = savemiplevel;
2582         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2583         {
2584                 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);
2585 #ifndef USE_GLES2
2586                 if (r_savedds && skinframe->reflect)
2587                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2588 #endif
2589                 Mem_Free(pixels);
2590                 pixels = NULL;
2591         }
2592
2593         if (basepixels)
2594                 Mem_Free(basepixels);
2595
2596         return skinframe;
2597 }
2598
2599 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)
2600 {
2601         int i;
2602         skinframe_t *skinframe;
2603         char vabuf[1024];
2604
2605         if (cls.state == ca_dedicated)
2606                 return NULL;
2607
2608         // if already loaded just return it, otherwise make a new skinframe
2609         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2610         if (skinframe->base)
2611                 return skinframe;
2612         textureflags &= ~TEXF_FORCE_RELOAD;
2613
2614         skinframe->stain = NULL;
2615         skinframe->merged = NULL;
2616         skinframe->base = NULL;
2617         skinframe->pants = NULL;
2618         skinframe->shirt = NULL;
2619         skinframe->nmap = NULL;
2620         skinframe->gloss = NULL;
2621         skinframe->glow = NULL;
2622         skinframe->fog = NULL;
2623         skinframe->reflect = NULL;
2624         skinframe->hasalpha = false;
2625
2626         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2627         if (!skindata)
2628                 return NULL;
2629
2630         if (developer_loading.integer)
2631                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2632
2633         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2634         {
2635                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2636                 unsigned char *b = a + width * height * 4;
2637                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2638                 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);
2639                 Mem_Free(a);
2640         }
2641         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2642         if (textureflags & TEXF_ALPHA)
2643         {
2644                 for (i = 3;i < width * height * 4;i += 4)
2645                 {
2646                         if (skindata[i] < 255)
2647                         {
2648                                 skinframe->hasalpha = true;
2649                                 break;
2650                         }
2651                 }
2652                 if (r_loadfog && skinframe->hasalpha)
2653                 {
2654                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2655                         memcpy(fogpixels, skindata, width * height * 4);
2656                         for (i = 0;i < width * height * 4;i += 4)
2657                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2658                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2659                         Mem_Free(fogpixels);
2660                 }
2661         }
2662
2663         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2664         //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]);
2665
2666         return skinframe;
2667 }
2668
2669 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2670 {
2671         int i;
2672         int featuresmask;
2673         skinframe_t *skinframe;
2674
2675         if (cls.state == ca_dedicated)
2676                 return NULL;
2677
2678         // if already loaded just return it, otherwise make a new skinframe
2679         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2680         if (skinframe->base)
2681                 return skinframe;
2682         //textureflags &= ~TEXF_FORCE_RELOAD;
2683
2684         skinframe->stain = NULL;
2685         skinframe->merged = NULL;
2686         skinframe->base = NULL;
2687         skinframe->pants = NULL;
2688         skinframe->shirt = NULL;
2689         skinframe->nmap = NULL;
2690         skinframe->gloss = NULL;
2691         skinframe->glow = NULL;
2692         skinframe->fog = NULL;
2693         skinframe->reflect = NULL;
2694         skinframe->hasalpha = false;
2695
2696         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2697         if (!skindata)
2698                 return NULL;
2699
2700         if (developer_loading.integer)
2701                 Con_Printf("loading quake skin \"%s\"\n", name);
2702
2703         // 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)
2704         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2705         memcpy(skinframe->qpixels, skindata, width*height);
2706         skinframe->qwidth = width;
2707         skinframe->qheight = height;
2708
2709         featuresmask = 0;
2710         for (i = 0;i < width * height;i++)
2711                 featuresmask |= palette_featureflags[skindata[i]];
2712
2713         skinframe->hasalpha = false;
2714         // fence textures
2715         if (name[0] == '{')
2716                 skinframe->hasalpha = true;
2717         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2718         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2719         skinframe->qgeneratemerged = true;
2720         skinframe->qgeneratebase = skinframe->qhascolormapping;
2721         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2722
2723         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2724         //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]);
2725
2726         return skinframe;
2727 }
2728
2729 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2730 {
2731         int width;
2732         int height;
2733         unsigned char *skindata;
2734         char vabuf[1024];
2735
2736         if (!skinframe->qpixels)
2737                 return;
2738
2739         if (!skinframe->qhascolormapping)
2740                 colormapped = false;
2741
2742         if (colormapped)
2743         {
2744                 if (!skinframe->qgeneratebase)
2745                         return;
2746         }
2747         else
2748         {
2749                 if (!skinframe->qgeneratemerged)
2750                         return;
2751         }
2752
2753         width = skinframe->qwidth;
2754         height = skinframe->qheight;
2755         skindata = skinframe->qpixels;
2756
2757         if (skinframe->qgeneratenmap)
2758         {
2759                 unsigned char *a, *b;
2760                 skinframe->qgeneratenmap = false;
2761                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2762                 b = a + width * height * 4;
2763                 // use either a custom palette or the quake palette
2764                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2765                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2766                 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);
2767                 Mem_Free(a);
2768         }
2769
2770         if (skinframe->qgenerateglow)
2771         {
2772                 skinframe->qgenerateglow = false;
2773                 if (skinframe->hasalpha) // fence textures
2774                         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
2775                 else
2776                         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
2777         }
2778
2779         if (colormapped)
2780         {
2781                 skinframe->qgeneratebase = false;
2782                 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);
2783                 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);
2784                 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);
2785         }
2786         else
2787         {
2788                 skinframe->qgeneratemerged = false;
2789                 if (skinframe->hasalpha) // fence textures
2790                         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);
2791                 else
2792                         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);
2793         }
2794
2795         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2796         {
2797                 Mem_Free(skinframe->qpixels);
2798                 skinframe->qpixels = NULL;
2799         }
2800 }
2801
2802 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)
2803 {
2804         int i;
2805         skinframe_t *skinframe;
2806         char vabuf[1024];
2807
2808         if (cls.state == ca_dedicated)
2809                 return NULL;
2810
2811         // if already loaded just return it, otherwise make a new skinframe
2812         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2813         if (skinframe->base)
2814                 return skinframe;
2815         textureflags &= ~TEXF_FORCE_RELOAD;
2816
2817         skinframe->stain = NULL;
2818         skinframe->merged = NULL;
2819         skinframe->base = NULL;
2820         skinframe->pants = NULL;
2821         skinframe->shirt = NULL;
2822         skinframe->nmap = NULL;
2823         skinframe->gloss = NULL;
2824         skinframe->glow = NULL;
2825         skinframe->fog = NULL;
2826         skinframe->reflect = NULL;
2827         skinframe->hasalpha = false;
2828
2829         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2830         if (!skindata)
2831                 return NULL;
2832
2833         if (developer_loading.integer)
2834                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2835
2836         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2837         if ((textureflags & TEXF_ALPHA) && alphapalette)
2838         {
2839                 for (i = 0;i < width * height;i++)
2840                 {
2841                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2842                         {
2843                                 skinframe->hasalpha = true;
2844                                 break;
2845                         }
2846                 }
2847                 if (r_loadfog && skinframe->hasalpha)
2848                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2849         }
2850
2851         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2852         //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]);
2853
2854         return skinframe;
2855 }
2856
2857 skinframe_t *R_SkinFrame_LoadMissing(void)
2858 {
2859         skinframe_t *skinframe;
2860
2861         if (cls.state == ca_dedicated)
2862                 return NULL;
2863
2864         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2865         skinframe->stain = NULL;
2866         skinframe->merged = NULL;
2867         skinframe->base = NULL;
2868         skinframe->pants = NULL;
2869         skinframe->shirt = NULL;
2870         skinframe->nmap = NULL;
2871         skinframe->gloss = NULL;
2872         skinframe->glow = NULL;
2873         skinframe->fog = NULL;
2874         skinframe->reflect = NULL;
2875         skinframe->hasalpha = false;
2876
2877         skinframe->avgcolor[0] = rand() / RAND_MAX;
2878         skinframe->avgcolor[1] = rand() / RAND_MAX;
2879         skinframe->avgcolor[2] = rand() / RAND_MAX;
2880         skinframe->avgcolor[3] = 1;
2881
2882         return skinframe;
2883 }
2884
2885 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2886 {
2887         int x, y;
2888         static unsigned char pix[16][16][4];
2889
2890         if (cls.state == ca_dedicated)
2891                 return NULL;
2892
2893         // this makes a light grey/dark grey checkerboard texture
2894         if (!pix[0][0][3])
2895         {
2896                 for (y = 0; y < 16; y++)
2897                 {
2898                         for (x = 0; x < 16; x++)
2899                         {
2900                                 if ((y < 8) ^ (x < 8))
2901                                 {
2902                                         pix[y][x][0] = 128;
2903                                         pix[y][x][1] = 128;
2904                                         pix[y][x][2] = 128;
2905                                         pix[y][x][3] = 255;
2906                                 }
2907                                 else
2908                                 {
2909                                         pix[y][x][0] = 64;
2910                                         pix[y][x][1] = 64;
2911                                         pix[y][x][2] = 64;
2912                                         pix[y][x][3] = 255;
2913                                 }
2914                         }
2915                 }
2916         }
2917
2918         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, 0, 0, 0, false);
2919 }
2920
2921 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2922 {
2923         skinframe_t *skinframe;
2924         if (cls.state == ca_dedicated)
2925                 return NULL;
2926         // if already loaded just return it, otherwise make a new skinframe
2927         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2928         if (skinframe->base)
2929                 return skinframe;
2930         textureflags &= ~TEXF_FORCE_RELOAD;
2931         skinframe->stain = NULL;
2932         skinframe->merged = NULL;
2933         skinframe->base = NULL;
2934         skinframe->pants = NULL;
2935         skinframe->shirt = NULL;
2936         skinframe->nmap = NULL;
2937         skinframe->gloss = NULL;
2938         skinframe->glow = NULL;
2939         skinframe->fog = NULL;
2940         skinframe->reflect = NULL;
2941         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2942         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2943         if (!tex)
2944                 return NULL;
2945         if (developer_loading.integer)
2946                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2947         skinframe->base = skinframe->merged = tex;
2948         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2949         return skinframe;
2950 }
2951
2952 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2953 typedef struct suffixinfo_s
2954 {
2955         const char *suffix;
2956         qboolean flipx, flipy, flipdiagonal;
2957 }
2958 suffixinfo_t;
2959 static suffixinfo_t suffix[3][6] =
2960 {
2961         {
2962                 {"px",   false, false, false},
2963                 {"nx",   false, false, false},
2964                 {"py",   false, false, false},
2965                 {"ny",   false, false, false},
2966                 {"pz",   false, false, false},
2967                 {"nz",   false, false, false}
2968         },
2969         {
2970                 {"posx", false, false, false},
2971                 {"negx", false, false, false},
2972                 {"posy", false, false, false},
2973                 {"negy", false, false, false},
2974                 {"posz", false, false, false},
2975                 {"negz", false, false, false}
2976         },
2977         {
2978                 {"rt",    true, false,  true},
2979                 {"lf",   false,  true,  true},
2980                 {"ft",    true,  true, false},
2981                 {"bk",   false, false, false},
2982                 {"up",    true, false,  true},
2983                 {"dn",    true, false,  true}
2984         }
2985 };
2986
2987 static int componentorder[4] = {0, 1, 2, 3};
2988
2989 static rtexture_t *R_LoadCubemap(const char *basename)
2990 {
2991         int i, j, cubemapsize, forcefilter;
2992         char name[256];
2993         unsigned char *cubemappixels, *image_buffer;
2994         rtexture_t *cubemaptexture;
2995         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2996         forcefilter = TEXF_FORCELINEAR;
2997         if (basename && basename[0] == '!')
2998         {
2999                 basename++;
3000                 forcefilter = TEXF_FORCENEAREST;
3001         }
3002         // must start 0 so the first loadimagepixels has no requested width/height
3003         cubemapsize = 0;
3004         cubemappixels = NULL;
3005         cubemaptexture = NULL;
3006         // keep trying different suffix groups (posx, px, rt) until one loads
3007         for (j = 0;j < 3 && !cubemappixels;j++)
3008         {
3009                 // load the 6 images in the suffix group
3010                 for (i = 0;i < 6;i++)
3011                 {
3012                         // generate an image name based on the base and and suffix
3013                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
3014                         // load it
3015                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
3016                         {
3017                                 // an image loaded, make sure width and height are equal
3018                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
3019                                 {
3020                                         // if this is the first image to load successfully, allocate the cubemap memory
3021                                         if (!cubemappixels && image_width >= 1)
3022                                         {
3023                                                 cubemapsize = image_width;
3024                                                 // note this clears to black, so unavailable sides are black
3025                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
3026                                         }
3027                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
3028                                         if (cubemappixels)
3029                                                 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);
3030                                 }
3031                                 else
3032                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
3033                                 // free the image
3034                                 Mem_Free(image_buffer);
3035                         }
3036                 }
3037         }
3038         // if a cubemap loaded, upload it
3039         if (cubemappixels)
3040         {
3041                 if (developer_loading.integer)
3042                         Con_Printf("loading cubemap \"%s\"\n", basename);
3043
3044                 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);
3045                 Mem_Free(cubemappixels);
3046         }
3047         else
3048         {
3049                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
3050                 if (developer_loading.integer)
3051                 {
3052                         Con_Printf("(tried tried images ");
3053                         for (j = 0;j < 3;j++)
3054                                 for (i = 0;i < 6;i++)
3055                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
3056                         Con_Print(" and was unable to find any of them).\n");
3057                 }
3058         }
3059         return cubemaptexture;
3060 }
3061
3062 rtexture_t *R_GetCubemap(const char *basename)
3063 {
3064         int i;
3065         for (i = 0;i < r_texture_numcubemaps;i++)
3066                 if (r_texture_cubemaps[i] != NULL)
3067                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
3068                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
3069         if (i >= MAX_CUBEMAPS || !r_main_mempool)
3070                 return r_texture_whitecube;
3071         r_texture_numcubemaps++;
3072         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
3073         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
3074         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
3075         return r_texture_cubemaps[i]->texture;
3076 }
3077
3078 static void R_Main_FreeViewCache(void)
3079 {
3080         if (r_refdef.viewcache.entityvisible)
3081                 Mem_Free(r_refdef.viewcache.entityvisible);
3082         if (r_refdef.viewcache.world_pvsbits)
3083                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3084         if (r_refdef.viewcache.world_leafvisible)
3085                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3086         if (r_refdef.viewcache.world_surfacevisible)
3087                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3088         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3089 }
3090
3091 static void R_Main_ResizeViewCache(void)
3092 {
3093         int numentities = r_refdef.scene.numentities;
3094         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3095         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3096         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3097         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3098         if (r_refdef.viewcache.maxentities < numentities)
3099         {
3100                 r_refdef.viewcache.maxentities = numentities;
3101                 if (r_refdef.viewcache.entityvisible)
3102                         Mem_Free(r_refdef.viewcache.entityvisible);
3103                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3104         }
3105         if (r_refdef.viewcache.world_numclusters != numclusters)
3106         {
3107                 r_refdef.viewcache.world_numclusters = numclusters;
3108                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3109                 if (r_refdef.viewcache.world_pvsbits)
3110                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3111                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3112         }
3113         if (r_refdef.viewcache.world_numleafs != numleafs)
3114         {
3115                 r_refdef.viewcache.world_numleafs = numleafs;
3116                 if (r_refdef.viewcache.world_leafvisible)
3117                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3118                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3119         }
3120         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3121         {
3122                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3123                 if (r_refdef.viewcache.world_surfacevisible)
3124                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3125                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3126         }
3127 }
3128
3129 extern rtexture_t *loadingscreentexture;
3130 static void gl_main_start(void)
3131 {
3132         loadingscreentexture = NULL;
3133         r_texture_blanknormalmap = NULL;
3134         r_texture_white = NULL;
3135         r_texture_grey128 = NULL;
3136         r_texture_black = NULL;
3137         r_texture_whitecube = NULL;
3138         r_texture_normalizationcube = NULL;
3139         r_texture_fogattenuation = NULL;
3140         r_texture_fogheighttexture = NULL;
3141         r_texture_lut = NULL;
3142         r_texture_lut_default = NULL;
3143         r_texture_gammaramps = NULL;
3144         r_texture_numcubemaps = 0;
3145         r_uniformbufferalignment = 32;
3146
3147         r_loaddds = r_texture_dds_load.integer != 0;
3148         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3149
3150         switch(vid.renderpath)
3151         {
3152         case RENDERPATH_GL32:
3153         case RENDERPATH_GLES2:
3154                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3155                 Cvar_SetValueQuick(&gl_combine, 1);
3156                 Cvar_SetValueQuick(&r_glsl, 1);
3157                 r_loadnormalmap = true;
3158                 r_loadgloss = true;
3159                 r_loadfog = false;
3160 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3161                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3162 #endif
3163                 break;
3164         }
3165
3166         R_AnimCache_Free();
3167         R_FrameData_Reset();
3168         R_BufferData_Reset();
3169
3170         r_numqueries = 0;
3171         r_maxqueries = 0;
3172         memset(r_queries, 0, sizeof(r_queries));
3173
3174         r_qwskincache = NULL;
3175         r_qwskincache_size = 0;
3176
3177         // due to caching of texture_t references, the collision cache must be reset
3178         Collision_Cache_Reset(true);
3179
3180         // set up r_skinframe loading system for textures
3181         memset(&r_skinframe, 0, sizeof(r_skinframe));
3182         r_skinframe.loadsequence = 1;
3183         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3184
3185         r_main_texturepool = R_AllocTexturePool();
3186         R_BuildBlankTextures();
3187         R_BuildNoTexture();
3188         R_BuildWhiteCube();
3189         R_BuildNormalizationCube();
3190         R_BuildDefaultLUT();
3191         r_texture_fogattenuation = NULL;
3192         r_texture_fogheighttexture = NULL;
3193         r_texture_gammaramps = NULL;
3194         //r_texture_fogintensity = NULL;
3195         memset(&r_fb, 0, sizeof(r_fb));
3196         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3197         r_glsl_permutation = NULL;
3198         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3199         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3200         memset(&r_svbsp, 0, sizeof (r_svbsp));
3201
3202         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3203         r_texture_numcubemaps = 0;
3204
3205         r_refdef.fogmasktable_density = 0;
3206
3207 #ifdef __ANDROID__
3208         // For Steelstorm Android
3209         // FIXME CACHE the program and reload
3210         // FIXME see possible combinations for SS:BR android
3211         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3212         R_SetupShader_SetPermutationGLSL(0, 12);
3213         R_SetupShader_SetPermutationGLSL(0, 13);
3214         R_SetupShader_SetPermutationGLSL(0, 8388621);
3215         R_SetupShader_SetPermutationGLSL(3, 0);
3216         R_SetupShader_SetPermutationGLSL(3, 2048);
3217         R_SetupShader_SetPermutationGLSL(5, 0);
3218         R_SetupShader_SetPermutationGLSL(5, 2);
3219         R_SetupShader_SetPermutationGLSL(5, 2048);
3220         R_SetupShader_SetPermutationGLSL(5, 8388608);
3221         R_SetupShader_SetPermutationGLSL(11, 1);
3222         R_SetupShader_SetPermutationGLSL(11, 2049);
3223         R_SetupShader_SetPermutationGLSL(11, 8193);
3224         R_SetupShader_SetPermutationGLSL(11, 10241);
3225         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3226 #endif
3227 }
3228
3229 extern unsigned int r_shadow_occlusion_buf;
3230
3231 static void gl_main_shutdown(void)
3232 {
3233         R_RenderTarget_FreeUnused(true);
3234         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3235         R_AnimCache_Free();
3236         R_FrameData_Reset();
3237         R_BufferData_Reset();
3238
3239         R_Main_FreeViewCache();
3240
3241         switch(vid.renderpath)
3242         {
3243         case RENDERPATH_GL32:
3244         case RENDERPATH_GLES2:
3245 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3246                 if (r_maxqueries)
3247                         qglDeleteQueries(r_maxqueries, r_queries);
3248 #endif
3249                 break;
3250         }
3251         r_shadow_occlusion_buf = 0;
3252         r_numqueries = 0;
3253         r_maxqueries = 0;
3254         memset(r_queries, 0, sizeof(r_queries));
3255
3256         r_qwskincache = NULL;
3257         r_qwskincache_size = 0;
3258
3259         // clear out the r_skinframe state
3260         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3261         memset(&r_skinframe, 0, sizeof(r_skinframe));
3262
3263         if (r_svbsp.nodes)
3264                 Mem_Free(r_svbsp.nodes);
3265         memset(&r_svbsp, 0, sizeof (r_svbsp));
3266         R_FreeTexturePool(&r_main_texturepool);
3267         loadingscreentexture = NULL;
3268         r_texture_blanknormalmap = NULL;
3269         r_texture_white = NULL;
3270         r_texture_grey128 = NULL;
3271         r_texture_black = NULL;
3272         r_texture_whitecube = NULL;
3273         r_texture_normalizationcube = NULL;
3274         r_texture_fogattenuation = NULL;
3275         r_texture_fogheighttexture = NULL;
3276         r_texture_lut = NULL;
3277         r_texture_lut_default = NULL;
3278         r_texture_gammaramps = NULL;
3279         r_texture_numcubemaps = 0;
3280         //r_texture_fogintensity = NULL;
3281         memset(&r_fb, 0, sizeof(r_fb));
3282         R_GLSL_Restart_f(&cmd_client);
3283
3284         r_glsl_permutation = NULL;
3285         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3286         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3287 }
3288
3289 static void gl_main_newmap(void)
3290 {
3291         // FIXME: move this code to client
3292         char *entities, entname[MAX_QPATH];
3293         if (r_qwskincache)
3294                 Mem_Free(r_qwskincache);
3295         r_qwskincache = NULL;
3296         r_qwskincache_size = 0;
3297         if (cl.worldmodel)
3298         {
3299                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3300                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3301                 {
3302                         CL_ParseEntityLump(entities);
3303                         Mem_Free(entities);
3304                         return;
3305                 }
3306                 if (cl.worldmodel->brush.entities)
3307                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3308         }
3309         R_Main_FreeViewCache();
3310
3311         R_FrameData_Reset();
3312         R_BufferData_Reset();
3313 }
3314
3315 void GL_Main_Init(void)
3316 {
3317         int i;
3318         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3319         R_InitShaderModeInfo();
3320
3321         Cmd_AddCommand(&cmd_client, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3322         Cmd_AddCommand(&cmd_client, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3323         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3324         if (gamemode == GAME_NEHAHRA)
3325         {
3326                 Cvar_RegisterVariable (&gl_fogenable);
3327                 Cvar_RegisterVariable (&gl_fogdensity);
3328                 Cvar_RegisterVariable (&gl_fogred);
3329                 Cvar_RegisterVariable (&gl_foggreen);
3330                 Cvar_RegisterVariable (&gl_fogblue);
3331                 Cvar_RegisterVariable (&gl_fogstart);
3332                 Cvar_RegisterVariable (&gl_fogend);
3333                 Cvar_RegisterVariable (&gl_skyclip);
3334         }
3335         Cvar_RegisterVariable(&r_motionblur);
3336         Cvar_RegisterVariable(&r_damageblur);
3337         Cvar_RegisterVariable(&r_motionblur_averaging);
3338         Cvar_RegisterVariable(&r_motionblur_randomize);
3339         Cvar_RegisterVariable(&r_motionblur_minblur);
3340         Cvar_RegisterVariable(&r_motionblur_maxblur);
3341         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3342         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3343         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3344         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3345         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3346         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3347         Cvar_RegisterVariable(&r_depthfirst);
3348         Cvar_RegisterVariable(&r_useinfinitefarclip);
3349         Cvar_RegisterVariable(&r_farclip_base);
3350         Cvar_RegisterVariable(&r_farclip_world);
3351         Cvar_RegisterVariable(&r_nearclip);
3352         Cvar_RegisterVariable(&r_deformvertexes);
3353         Cvar_RegisterVariable(&r_transparent);
3354         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3355         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3356         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3357         Cvar_RegisterVariable(&r_showoverdraw);
3358         Cvar_RegisterVariable(&r_showbboxes);
3359         Cvar_RegisterVariable(&r_showbboxes_client);
3360         Cvar_RegisterVariable(&r_showsurfaces);
3361         Cvar_RegisterVariable(&r_showtris);
3362         Cvar_RegisterVariable(&r_shownormals);
3363         Cvar_RegisterVariable(&r_showlighting);
3364         Cvar_RegisterVariable(&r_showcollisionbrushes);
3365         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3366         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3367         Cvar_RegisterVariable(&r_showdisabledepthtest);
3368         Cvar_RegisterVariable(&r_showspriteedges);
3369         Cvar_RegisterVariable(&r_showparticleedges);
3370         Cvar_RegisterVariable(&r_drawportals);
3371         Cvar_RegisterVariable(&r_drawentities);
3372         Cvar_RegisterVariable(&r_draw2d);
3373         Cvar_RegisterVariable(&r_drawworld);
3374         Cvar_RegisterVariable(&r_cullentities_trace);
3375         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3376         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3377         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3378         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3379         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3380         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3381         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3382         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3383         Cvar_RegisterVariable(&r_sortentities);
3384         Cvar_RegisterVariable(&r_drawviewmodel);
3385         Cvar_RegisterVariable(&r_drawexteriormodel);
3386         Cvar_RegisterVariable(&r_speeds);
3387         Cvar_RegisterVariable(&r_fullbrights);
3388         Cvar_RegisterVariable(&r_wateralpha);
3389         Cvar_RegisterVariable(&r_dynamic);
3390         Cvar_RegisterVariable(&r_fullbright_directed);
3391         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3392         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3393         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3394         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3395         Cvar_RegisterVariable(&r_fullbright);
3396         Cvar_RegisterVariable(&r_shadows);
3397         Cvar_RegisterVariable(&r_shadows_darken);
3398         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3399         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3400         Cvar_RegisterVariable(&r_shadows_throwdistance);
3401         Cvar_RegisterVariable(&r_shadows_throwdirection);
3402         Cvar_RegisterVariable(&r_shadows_focus);
3403         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3404         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3405         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3406         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3407         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3408         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3409         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3410         Cvar_RegisterVariable(&r_fog_exp2);
3411         Cvar_RegisterVariable(&r_fog_clear);
3412         Cvar_RegisterVariable(&r_drawfog);
3413         Cvar_RegisterVariable(&r_transparentdepthmasking);
3414         Cvar_RegisterVariable(&r_transparent_sortmindist);
3415         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3416         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3417         Cvar_RegisterVariable(&r_texture_dds_load);
3418         Cvar_RegisterVariable(&r_texture_dds_save);
3419         Cvar_RegisterVariable(&r_textureunits);
3420         Cvar_RegisterVariable(&gl_combine);
3421         Cvar_RegisterVariable(&r_usedepthtextures);
3422         Cvar_RegisterVariable(&r_viewfbo);
3423         Cvar_RegisterVariable(&r_rendertarget_debug);
3424         Cvar_RegisterVariable(&r_viewscale);
3425         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3426         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3427         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3428         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3429         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3430         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3431         Cvar_RegisterVariable(&r_glsl);
3432         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3433         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3434         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3435         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3436         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3437         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3438         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3439         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3440         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3441         Cvar_RegisterVariable(&r_glsl_postprocess);
3442         Cvar_RegisterVariable(&r_glsl_postprocess_color_lut);
3443         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3444         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3445         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3446         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3447         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3448         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3449         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3450         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3451         Cvar_RegisterVariable(&r_celshading);
3452         Cvar_RegisterVariable(&r_celoutlines);
3453
3454         Cvar_RegisterVariable(&r_water);
3455         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3456         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3457         Cvar_RegisterVariable(&r_water_clippingplanebias);
3458         Cvar_RegisterVariable(&r_water_refractdistort);
3459         Cvar_RegisterVariable(&r_water_reflectdistort);
3460         Cvar_RegisterVariable(&r_water_scissormode);
3461         Cvar_RegisterVariable(&r_water_lowquality);
3462         Cvar_RegisterVariable(&r_water_hideplayer);
3463
3464         Cvar_RegisterVariable(&r_lerpsprites);
3465         Cvar_RegisterVariable(&r_lerpmodels);
3466         Cvar_RegisterVariable(&r_lerplightstyles);
3467         Cvar_RegisterVariable(&r_waterscroll);
3468         Cvar_RegisterVariable(&r_bloom);
3469         Cvar_RegisterVariable(&r_colorfringe);
3470         Cvar_RegisterVariable(&r_bloom_colorscale);
3471         Cvar_RegisterVariable(&r_bloom_brighten);
3472         Cvar_RegisterVariable(&r_bloom_blur);
3473         Cvar_RegisterVariable(&r_bloom_resolution);
3474         Cvar_RegisterVariable(&r_bloom_colorexponent);
3475         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3476         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3477         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3478         Cvar_RegisterVariable(&r_hdr_glowintensity);
3479         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3480         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3481         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3482         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3483         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3484         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3485         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3486         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3487         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3488         Cvar_RegisterVariable(&developer_texturelogging);
3489         Cvar_RegisterVariable(&gl_lightmaps);
3490         Cvar_RegisterVariable(&r_test);
3491         Cvar_RegisterVariable(&r_batch_multidraw);
3492         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3493         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3494         Cvar_RegisterVariable(&r_glsl_skeletal);
3495         Cvar_RegisterVariable(&r_glsl_saturation);
3496         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3497         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3498         Cvar_RegisterVariable(&r_framedatasize);
3499         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3500                 Cvar_RegisterVariable(&r_buffermegs[i]);
3501         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3502         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3503                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3504 #ifdef DP_MOBILETOUCH
3505         // GLES devices have terrible depth precision in general, so...
3506         Cvar_SetValueQuick(&r_nearclip, 4);
3507         Cvar_SetValueQuick(&r_farclip_base, 4096);
3508         Cvar_SetValueQuick(&r_farclip_world, 0);
3509         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3510 #endif
3511         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3512 }
3513
3514 void Render_Init(void)
3515 {
3516         gl_backend_init();
3517         R_Textures_Init();
3518         GL_Main_Init();
3519         Font_Init();
3520         GL_Draw_Init();
3521         R_Shadow_Init();
3522         R_Sky_Init();
3523         GL_Surf_Init();
3524         Sbar_Init();
3525         R_Particles_Init();
3526         R_Explosion_Init();
3527         R_LightningBeams_Init();
3528         Mod_RenderInit();
3529 }
3530
3531 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3532 {
3533         int i;
3534         mplane_t *p;
3535         if (r_trippy.integer)
3536                 return false;
3537         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3538         {
3539                 p = r_refdef.view.frustum + i;
3540                 switch(p->signbits)
3541                 {
3542                 default:
3543                 case 0:
3544                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3545                                 return true;
3546                         break;
3547                 case 1:
3548                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3549                                 return true;
3550                         break;
3551                 case 2:
3552                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3553                                 return true;
3554                         break;
3555                 case 3:
3556                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3557                                 return true;
3558                         break;
3559                 case 4:
3560                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3561                                 return true;
3562                         break;
3563                 case 5:
3564                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3565                                 return true;
3566                         break;
3567                 case 6:
3568                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3569                                 return true;
3570                         break;
3571                 case 7:
3572                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3573                                 return true;
3574                         break;
3575                 }
3576         }
3577         return false;
3578 }
3579
3580 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3581 {
3582         int i;
3583         const mplane_t *p;
3584         if (r_trippy.integer)
3585                 return false;
3586         for (i = 0;i < numplanes;i++)
3587         {
3588                 p = planes + i;
3589                 switch(p->signbits)
3590                 {
3591                 default:
3592                 case 0:
3593                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3594                                 return true;
3595                         break;
3596                 case 1:
3597                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3598                                 return true;
3599                         break;
3600                 case 2:
3601                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3602                                 return true;
3603                         break;
3604                 case 3:
3605                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3606                                 return true;
3607                         break;
3608                 case 4:
3609                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3610                                 return true;
3611                         break;
3612                 case 5:
3613                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3614                                 return true;
3615                         break;
3616                 case 6:
3617                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3618                                 return true;
3619                         break;
3620                 case 7:
3621                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3622                                 return true;
3623                         break;
3624                 }
3625         }
3626         return false;
3627 }
3628
3629 //==================================================================================
3630
3631 // LadyHavoc: this stores temporary data used within the same frame
3632
3633 typedef struct r_framedata_mem_s
3634 {
3635         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3636         size_t size; // how much usable space
3637         size_t current; // how much space in use
3638         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3639         size_t wantedsize; // how much space was allocated
3640         unsigned char *data; // start of real data (16byte aligned)
3641 }
3642 r_framedata_mem_t;
3643
3644 static r_framedata_mem_t *r_framedata_mem;
3645
3646 void R_FrameData_Reset(void)
3647 {
3648         while (r_framedata_mem)
3649         {
3650                 r_framedata_mem_t *next = r_framedata_mem->purge;
3651                 Mem_Free(r_framedata_mem);
3652                 r_framedata_mem = next;
3653         }
3654 }
3655
3656 static void R_FrameData_Resize(qboolean mustgrow)
3657 {
3658         size_t wantedsize;
3659         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3660         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3661         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3662         {
3663                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3664                 newmem->wantedsize = wantedsize;
3665                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3666                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3667                 newmem->current = 0;
3668                 newmem->mark = 0;
3669                 newmem->purge = r_framedata_mem;
3670                 r_framedata_mem = newmem;
3671         }
3672 }
3673
3674 void R_FrameData_NewFrame(void)
3675 {
3676         R_FrameData_Resize(false);
3677         if (!r_framedata_mem)
3678                 return;
3679         // if we ran out of space on the last frame, free the old memory now
3680         while (r_framedata_mem->purge)
3681         {
3682                 // repeatedly remove the second item in the list, leaving only head
3683                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3684                 Mem_Free(r_framedata_mem->purge);
3685                 r_framedata_mem->purge = next;
3686         }
3687         // reset the current mem pointer
3688         r_framedata_mem->current = 0;
3689         r_framedata_mem->mark = 0;
3690 }
3691
3692 void *R_FrameData_Alloc(size_t size)
3693 {
3694         void *data;
3695         float newvalue;
3696
3697         // align to 16 byte boundary - the data pointer is already aligned, so we
3698         // only need to ensure the size of every allocation is also aligned
3699         size = (size + 15) & ~15;
3700
3701         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3702         {
3703                 // emergency - we ran out of space, allocate more memory
3704                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3705                 newvalue = r_framedatasize.value * 2.0f;
3706                 // 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
3707                 if (sizeof(size_t) >= 8)
3708                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3709                 else
3710                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3711                 // this might not be a growing it, but we'll allocate another buffer every time
3712                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3713                 R_FrameData_Resize(true);
3714         }
3715
3716         data = r_framedata_mem->data + r_framedata_mem->current;
3717         r_framedata_mem->current += size;
3718
3719         // count the usage for stats
3720         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3721         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3722
3723         return (void *)data;
3724 }
3725
3726 void *R_FrameData_Store(size_t size, void *data)
3727 {
3728         void *d = R_FrameData_Alloc(size);
3729         if (d && data)
3730                 memcpy(d, data, size);
3731         return d;
3732 }
3733
3734 void R_FrameData_SetMark(void)
3735 {
3736         if (!r_framedata_mem)
3737                 return;
3738         r_framedata_mem->mark = r_framedata_mem->current;
3739 }
3740
3741 void R_FrameData_ReturnToMark(void)
3742 {
3743         if (!r_framedata_mem)
3744                 return;
3745         r_framedata_mem->current = r_framedata_mem->mark;
3746 }
3747
3748 //==================================================================================
3749
3750 // avoid reusing the same buffer objects on consecutive frames
3751 #define R_BUFFERDATA_CYCLE 3
3752
3753 typedef struct r_bufferdata_buffer_s
3754 {
3755         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3756         size_t size; // how much usable space
3757         size_t current; // how much space in use
3758         r_meshbuffer_t *buffer; // the buffer itself
3759 }
3760 r_bufferdata_buffer_t;
3761
3762 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3763 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3764
3765 /// frees all dynamic buffers
3766 void R_BufferData_Reset(void)
3767 {
3768         int cycle, type;
3769         r_bufferdata_buffer_t **p, *mem;
3770         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3771         {
3772                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3773                 {
3774                         // free all buffers
3775                         p = &r_bufferdata_buffer[cycle][type];
3776                         while (*p)
3777                         {
3778                                 mem = *p;
3779                                 *p = (*p)->purge;
3780                                 if (mem->buffer)
3781                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3782                                 Mem_Free(mem);
3783                         }
3784                 }
3785         }
3786 }
3787
3788 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3789 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3790 {
3791         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3792         size_t size;
3793         float newvalue = r_buffermegs[type].value;
3794
3795         // increase the cvar if we have to (but only if we already have a mem)
3796         if (mustgrow && mem)
3797                 newvalue *= 2.0f;
3798         newvalue = bound(0.25f, newvalue, 256.0f);
3799         while (newvalue * 1024*1024 < minsize)
3800                 newvalue *= 2.0f;
3801
3802         // clamp the cvar to valid range
3803         newvalue = bound(0.25f, newvalue, 256.0f);
3804         if (r_buffermegs[type].value != newvalue)
3805                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3806
3807         // calculate size in bytes
3808         size = (size_t)(newvalue * 1024*1024);
3809         size = bound(131072, size, 256*1024*1024);
3810
3811         // allocate a new buffer if the size is different (purge old one later)
3812         // or if we were told we must grow the buffer
3813         if (!mem || mem->size != size || mustgrow)
3814         {
3815                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3816                 mem->size = size;
3817                 mem->current = 0;
3818                 if (type == R_BUFFERDATA_VERTEX)
3819                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3820                 else if (type == R_BUFFERDATA_INDEX16)
3821                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3822                 else if (type == R_BUFFERDATA_INDEX32)
3823                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3824                 else if (type == R_BUFFERDATA_UNIFORM)
3825                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3826                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3827                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3828         }
3829 }
3830
3831 void R_BufferData_NewFrame(void)
3832 {
3833         int type;
3834         r_bufferdata_buffer_t **p, *mem;
3835         // cycle to the next frame's buffers
3836         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3837         // if we ran out of space on the last time we used these buffers, free the old memory now
3838         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3839         {
3840                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3841                 {
3842                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3843                         // free all but the head buffer, this is how we recycle obsolete
3844                         // buffers after they are no longer in use
3845                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3846                         while (*p)
3847                         {
3848                                 mem = *p;
3849                                 *p = (*p)->purge;
3850                                 if (mem->buffer)
3851                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3852                                 Mem_Free(mem);
3853                         }
3854                         // reset the current offset
3855                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3856                 }
3857         }
3858 }
3859
3860 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3861 {
3862         r_bufferdata_buffer_t *mem;
3863         int offset = 0;
3864         int padsize;
3865
3866         *returnbufferoffset = 0;
3867
3868         // align size to a byte boundary appropriate for the buffer type, this
3869         // makes all allocations have aligned start offsets
3870         if (type == R_BUFFERDATA_UNIFORM)
3871                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3872         else
3873                 padsize = (datasize + 15) & ~15;
3874
3875         // if we ran out of space in this buffer we must allocate a new one
3876         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)
3877                 R_BufferData_Resize(type, true, padsize);
3878
3879         // if the resize did not give us enough memory, fail
3880         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)
3881                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3882
3883         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3884         offset = (int)mem->current;
3885         mem->current += padsize;
3886
3887         // upload the data to the buffer at the chosen offset
3888         if (offset == 0)
3889                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3890         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3891
3892         // count the usage for stats
3893         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3894         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3895
3896         // return the buffer offset
3897         *returnbufferoffset = offset;
3898
3899         return mem->buffer;
3900 }
3901
3902 //==================================================================================
3903
3904 // LadyHavoc: animcache originally written by Echon, rewritten since then
3905
3906 /**
3907  * Animation cache prevents re-generating mesh data for an animated model
3908  * multiple times in one frame for lighting, shadowing, reflections, etc.
3909  */
3910
3911 void R_AnimCache_Free(void)
3912 {
3913 }
3914
3915 void R_AnimCache_ClearCache(void)
3916 {
3917         int i;
3918         entity_render_t *ent;
3919
3920         for (i = 0;i < r_refdef.scene.numentities;i++)
3921         {
3922                 ent = r_refdef.scene.entities[i];
3923                 ent->animcache_vertex3f = NULL;
3924                 ent->animcache_vertex3f_vertexbuffer = NULL;
3925                 ent->animcache_vertex3f_bufferoffset = 0;
3926                 ent->animcache_normal3f = NULL;
3927                 ent->animcache_normal3f_vertexbuffer = NULL;
3928                 ent->animcache_normal3f_bufferoffset = 0;
3929                 ent->animcache_svector3f = NULL;
3930                 ent->animcache_svector3f_vertexbuffer = NULL;
3931                 ent->animcache_svector3f_bufferoffset = 0;
3932                 ent->animcache_tvector3f = NULL;
3933                 ent->animcache_tvector3f_vertexbuffer = NULL;
3934                 ent->animcache_tvector3f_bufferoffset = 0;
3935                 ent->animcache_skeletaltransform3x4 = NULL;
3936                 ent->animcache_skeletaltransform3x4buffer = NULL;
3937                 ent->animcache_skeletaltransform3x4offset = 0;
3938                 ent->animcache_skeletaltransform3x4size = 0;
3939         }
3940 }
3941
3942 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3943 {
3944         dp_model_t *model = ent->model;
3945         int numvertices;
3946
3947         // see if this ent is worth caching
3948         if (!model || !model->Draw || !model->AnimateVertices)
3949                 return false;
3950         // nothing to cache if it contains no animations and has no skeleton
3951         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3952                 return false;
3953         // see if it is already cached for gpuskeletal
3954         if (ent->animcache_skeletaltransform3x4)
3955                 return false;
3956         // see if it is already cached as a mesh
3957         if (ent->animcache_vertex3f)
3958         {
3959                 // check if we need to add normals or tangents
3960                 if (ent->animcache_normal3f)
3961                         wantnormals = false;
3962                 if (ent->animcache_svector3f)
3963                         wanttangents = false;
3964                 if (!wantnormals && !wanttangents)
3965                         return false;
3966         }
3967
3968         // check which kind of cache we need to generate
3969         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3970         {
3971                 // cache the skeleton so the vertex shader can use it
3972                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3973                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3974                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3975                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3976                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3977                 // note: this can fail if the buffer is at the grow limit
3978                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3979                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3980         }
3981         else if (ent->animcache_vertex3f)
3982         {
3983                 // mesh was already cached but we may need to add normals/tangents
3984                 // (this only happens with multiple views, reflections, cameras, etc)
3985                 if (wantnormals || wanttangents)
3986                 {
3987                         numvertices = model->surfmesh.num_vertices;
3988                         if (wantnormals)
3989                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3990                         if (wanttangents)
3991                         {
3992                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3993                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3994                         }
3995                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3996                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3997                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3998                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3999                 }
4000         }
4001         else
4002         {
4003                 // generate mesh cache
4004                 numvertices = model->surfmesh.num_vertices;
4005                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
4006                 if (wantnormals)
4007                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
4008                 if (wanttangents)
4009                 {
4010                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
4011                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
4012                 }
4013                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
4014                 if (wantnormals || wanttangents)
4015                 {
4016                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
4017                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
4018                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
4019                 }
4020                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
4021                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
4022                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4023         }
4024         return true;
4025 }
4026
4027 void R_AnimCache_CacheVisibleEntities(void)
4028 {
4029         int i;
4030
4031         // TODO: thread this
4032         // NOTE: R_PrepareRTLights() also caches entities
4033
4034         for (i = 0;i < r_refdef.scene.numentities;i++)
4035                 if (r_refdef.viewcache.entityvisible[i])
4036                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4037 }
4038
4039 //==================================================================================
4040
4041 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)
4042 {
4043         long unsigned int i;
4044         int j;
4045         vec3_t eyemins, eyemaxs;
4046         vec3_t boxmins, boxmaxs;
4047         vec3_t padmins, padmaxs;
4048         vec3_t start;
4049         vec3_t end;
4050         dp_model_t *model = r_refdef.scene.worldmodel;
4051         static vec3_t positions[] = {
4052                 { 0.5f, 0.5f, 0.5f },
4053                 { 0.0f, 0.0f, 0.0f },
4054                 { 0.0f, 0.0f, 1.0f },
4055                 { 0.0f, 1.0f, 0.0f },
4056                 { 0.0f, 1.0f, 1.0f },
4057                 { 1.0f, 0.0f, 0.0f },
4058                 { 1.0f, 0.0f, 1.0f },
4059                 { 1.0f, 1.0f, 0.0f },
4060                 { 1.0f, 1.0f, 1.0f },
4061         };
4062
4063         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4064         if (numsamples < 0)
4065                 return true;
4066
4067         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4068         if (!r_refdef.view.usevieworiginculling)
4069                 return true;
4070
4071         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4072                 return true;
4073
4074         // expand the eye box a little
4075         eyemins[0] = eye[0] - eyejitter;
4076         eyemaxs[0] = eye[0] + eyejitter;
4077         eyemins[1] = eye[1] - eyejitter;
4078         eyemaxs[1] = eye[1] + eyejitter;
4079         eyemins[2] = eye[2] - eyejitter;
4080         eyemaxs[2] = eye[2] + eyejitter;
4081         // expand the box a little
4082         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4083         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4084         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4085         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4086         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4087         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4088         // make an even larger box for the acceptable area
4089         padmins[0] = boxmins[0] - pad;
4090         padmaxs[0] = boxmaxs[0] + pad;
4091         padmins[1] = boxmins[1] - pad;
4092         padmaxs[1] = boxmaxs[1] + pad;
4093         padmins[2] = boxmins[2] - pad;
4094         padmaxs[2] = boxmaxs[2] + pad;
4095
4096         // return true if eye overlaps enlarged box
4097         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4098                 return true;
4099
4100         // try specific positions in the box first - note that these can be cached
4101         if (r_cullentities_trace_entityocclusion.integer)
4102         {
4103                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4104                 {
4105                         trace_t trace;
4106                         VectorCopy(eye, start);
4107                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4108                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4109                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4110                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4111                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4112                         // not picky - if the trace ended anywhere in the box we're good
4113                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4114                                 return true;
4115                 }
4116         }
4117         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4118                 return true;
4119
4120         // try various random positions
4121         for (j = 0; j < numsamples; j++)
4122         {
4123                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4124                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4125                 if (r_cullentities_trace_entityocclusion.integer)
4126                 {
4127                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
4128                         // not picky - if the trace ended anywhere in the box we're good
4129                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4130                                 return true;
4131                 }
4132                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4133                         return true;
4134         }
4135
4136         return false;
4137 }
4138
4139
4140 static void R_View_UpdateEntityVisible (void)
4141 {
4142         int i;
4143         int renderimask;
4144         int samples;
4145         entity_render_t *ent;
4146
4147         if (r_refdef.envmap || r_fb.water.hideplayer)
4148                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4149         else if (chase_active.integer || r_fb.water.renderingscene)
4150                 renderimask = RENDER_VIEWMODEL;
4151         else
4152                 renderimask = RENDER_EXTERIORMODEL;
4153         if (!r_drawviewmodel.integer)
4154                 renderimask |= RENDER_VIEWMODEL;
4155         if (!r_drawexteriormodel.integer)
4156                 renderimask |= RENDER_EXTERIORMODEL;
4157         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4158         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4159         {
4160                 // worldmodel can check visibility
4161                 for (i = 0;i < r_refdef.scene.numentities;i++)
4162                 {
4163                         ent = r_refdef.scene.entities[i];
4164                         if (!(ent->flags & renderimask))
4165                         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)))
4166                         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))
4167                                 r_refdef.viewcache.entityvisible[i] = true;
4168                 }
4169         }
4170         else
4171         {
4172                 // no worldmodel or it can't check visibility
4173                 for (i = 0;i < r_refdef.scene.numentities;i++)
4174                 {
4175                         ent = r_refdef.scene.entities[i];
4176                         if (!(ent->flags & renderimask))
4177                         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)))
4178                                 r_refdef.viewcache.entityvisible[i] = true;
4179                 }
4180         }
4181         if (r_cullentities_trace.integer)
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                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4189                         {
4190                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4191                                 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))
4192                                         ent->last_trace_visibility = realtime;
4193                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4194                                         r_refdef.viewcache.entityvisible[i] = 0;
4195                         }
4196                 }
4197         }
4198 }
4199
4200 /// only used if skyrendermasked, and normally returns false
4201 static int R_DrawBrushModelsSky (void)
4202 {
4203         int i, sky;
4204         entity_render_t *ent;
4205
4206         sky = false;
4207         for (i = 0;i < r_refdef.scene.numentities;i++)
4208         {
4209                 if (!r_refdef.viewcache.entityvisible[i])
4210                         continue;
4211                 ent = r_refdef.scene.entities[i];
4212                 if (!ent->model || !ent->model->DrawSky)
4213                         continue;
4214                 ent->model->DrawSky(ent);
4215                 sky = true;
4216         }
4217         return sky;
4218 }
4219
4220 static void R_DrawNoModel(entity_render_t *ent);
4221 static void R_DrawModels(void)
4222 {
4223         int i;
4224         entity_render_t *ent;
4225
4226         for (i = 0;i < r_refdef.scene.numentities;i++)
4227         {
4228                 if (!r_refdef.viewcache.entityvisible[i])
4229                         continue;
4230                 ent = r_refdef.scene.entities[i];
4231                 r_refdef.stats[r_stat_entities]++;
4232                 /*
4233                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4234                 {
4235                         vec3_t f, l, u, o;
4236                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4237                         Con_Printf("R_DrawModels\n");
4238                         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]);
4239                         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);
4240                         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);
4241                 }
4242                 */
4243                 if (ent->model && ent->model->Draw != NULL)
4244                         ent->model->Draw(ent);
4245                 else
4246                         R_DrawNoModel(ent);
4247         }
4248 }
4249
4250 static void R_DrawModelsDepth(void)
4251 {
4252         int i;
4253         entity_render_t *ent;
4254
4255         for (i = 0;i < r_refdef.scene.numentities;i++)
4256         {
4257                 if (!r_refdef.viewcache.entityvisible[i])
4258                         continue;
4259                 ent = r_refdef.scene.entities[i];
4260                 if (ent->model && ent->model->DrawDepth != NULL)
4261                         ent->model->DrawDepth(ent);
4262         }
4263 }
4264
4265 static void R_DrawModelsDebug(void)
4266 {
4267         int i;
4268         entity_render_t *ent;
4269
4270         for (i = 0;i < r_refdef.scene.numentities;i++)
4271         {
4272                 if (!r_refdef.viewcache.entityvisible[i])
4273                         continue;
4274                 ent = r_refdef.scene.entities[i];
4275                 if (ent->model && ent->model->DrawDebug != NULL)
4276                         ent->model->DrawDebug(ent);
4277         }
4278 }
4279
4280 static void R_DrawModelsAddWaterPlanes(void)
4281 {
4282         int i;
4283         entity_render_t *ent;
4284
4285         for (i = 0;i < r_refdef.scene.numentities;i++)
4286         {
4287                 if (!r_refdef.viewcache.entityvisible[i])
4288                         continue;
4289                 ent = r_refdef.scene.entities[i];
4290                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4291                         ent->model->DrawAddWaterPlanes(ent);
4292         }
4293 }
4294
4295 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}};
4296
4297 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4298 {
4299         if (r_hdr_irisadaptation.integer)
4300         {
4301                 vec3_t p;
4302                 vec3_t ambient;
4303                 vec3_t diffuse;
4304                 vec3_t diffusenormal;
4305                 vec3_t forward;
4306                 vec_t brightness = 0.0f;
4307                 vec_t goal;
4308                 vec_t current;
4309                 vec_t d;
4310                 int c;
4311                 VectorCopy(r_refdef.view.forward, forward);
4312                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4313                 {
4314                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4315                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4316                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4317                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4318                         d = DotProduct(forward, diffusenormal);
4319                         brightness += VectorLength(ambient);
4320                         if (d > 0)
4321                                 brightness += d * VectorLength(diffuse);
4322                 }
4323                 brightness *= 1.0f / c;
4324                 brightness += 0.00001f; // make sure it's never zero
4325                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4326                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4327                 current = r_hdr_irisadaptation_value.value;
4328                 if (current < goal)
4329                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4330                 else if (current > goal)
4331                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4332                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4333                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4334         }
4335         else if (r_hdr_irisadaptation_value.value != 1.0f)
4336                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4337 }
4338
4339 static void R_View_SetFrustum(const int *scissor)
4340 {
4341         int i;
4342         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4343         vec3_t forward, left, up, origin, v;
4344
4345         if(scissor)
4346         {
4347                 // flipped x coordinates (because x points left here)
4348                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4349                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4350                 // non-flipped y coordinates
4351                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4352                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4353         }
4354
4355         // we can't trust r_refdef.view.forward and friends in reflected scenes
4356         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4357
4358 #if 0
4359         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4360         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4361         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4362         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4363         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4364         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4365         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4366         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4367         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4368         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4369         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4370         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4371 #endif
4372
4373 #if 0
4374         zNear = r_refdef.nearclip;
4375         nudge = 1.0 - 1.0 / (1<<23);
4376         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4377         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4378         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4379         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4380         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4381         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4382         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4383         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4384 #endif
4385
4386
4387
4388 #if 0
4389         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4390         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4391         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4392         r_refdef.view.frustum[0].dist = m[15] - m[12];
4393
4394         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4395         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4396         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4397         r_refdef.view.frustum[1].dist = m[15] + m[12];
4398
4399         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4400         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4401         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4402         r_refdef.view.frustum[2].dist = m[15] - m[13];
4403
4404         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4405         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4406         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4407         r_refdef.view.frustum[3].dist = m[15] + m[13];
4408
4409         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4410         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4411         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4412         r_refdef.view.frustum[4].dist = m[15] - m[14];
4413
4414         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4415         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4416         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4417         r_refdef.view.frustum[5].dist = m[15] + m[14];
4418 #endif
4419
4420         if (r_refdef.view.useperspective)
4421         {
4422                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4423                 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]);
4424                 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]);
4425                 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]);
4426                 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]);
4427
4428                 // then the normals from the corners relative to origin
4429                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4430                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4431                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4432                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4433
4434                 // in a NORMAL view, forward cross left == up
4435                 // in a REFLECTED view, forward cross left == down
4436                 // so our cross products above need to be adjusted for a left handed coordinate system
4437                 CrossProduct(forward, left, v);
4438                 if(DotProduct(v, up) < 0)
4439                 {
4440                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4441                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4442                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4443                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4444                 }
4445
4446                 // Leaving those out was a mistake, those were in the old code, and they
4447                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4448                 // I couldn't reproduce it after adding those normalizations. --blub
4449                 VectorNormalize(r_refdef.view.frustum[0].normal);
4450                 VectorNormalize(r_refdef.view.frustum[1].normal);
4451                 VectorNormalize(r_refdef.view.frustum[2].normal);
4452                 VectorNormalize(r_refdef.view.frustum[3].normal);
4453
4454                 // make the corners absolute
4455                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4456                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4457                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4458                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4459
4460                 // one more normal
4461                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4462
4463                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4464                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4465                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4466                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4467                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4468         }
4469         else
4470         {
4471                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4472                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4473                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4474                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4475                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4476                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4477                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4478                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4479                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4480                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4481         }
4482         r_refdef.view.numfrustumplanes = 5;
4483
4484         if (r_refdef.view.useclipplane)
4485         {
4486                 r_refdef.view.numfrustumplanes = 6;
4487                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4488         }
4489
4490         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4491                 PlaneClassify(r_refdef.view.frustum + i);
4492
4493         // LadyHavoc: note to all quake engine coders, Quake had a special case
4494         // for 90 degrees which assumed a square view (wrong), so I removed it,
4495         // Quake2 has it disabled as well.
4496
4497         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4498         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4499         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4500         //PlaneClassify(&frustum[0]);
4501
4502         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4503         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4504         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4505         //PlaneClassify(&frustum[1]);
4506
4507         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4508         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4509         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4510         //PlaneClassify(&frustum[2]);
4511
4512         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4513         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4514         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4515         //PlaneClassify(&frustum[3]);
4516
4517         // nearclip plane
4518         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4519         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4520         //PlaneClassify(&frustum[4]);
4521 }
4522
4523 static void R_View_UpdateWithScissor(const int *myscissor)
4524 {
4525         R_Main_ResizeViewCache();
4526         R_View_SetFrustum(myscissor);
4527         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4528         R_View_UpdateEntityVisible();
4529 }
4530
4531 static void R_View_Update(void)
4532 {
4533         R_Main_ResizeViewCache();
4534         R_View_SetFrustum(NULL);
4535         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4536         R_View_UpdateEntityVisible();
4537 }
4538
4539 float viewscalefpsadjusted = 1.0f;
4540
4541 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4542 {
4543         const float *customclipplane = NULL;
4544         float plane[4];
4545         int /*rtwidth,*/ rtheight;
4546         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4547         {
4548                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4549                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4550                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4551                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4552                         dist = r_refdef.view.clipplane.dist;
4553                 plane[0] = r_refdef.view.clipplane.normal[0];
4554                 plane[1] = r_refdef.view.clipplane.normal[1];
4555                 plane[2] = r_refdef.view.clipplane.normal[2];
4556                 plane[3] = -dist;
4557                 customclipplane = plane;
4558         }
4559
4560         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4561         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4562
4563         if (!r_refdef.view.useperspective)
4564                 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);
4565         else if (vid.stencil && r_useinfinitefarclip.integer)
4566                 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);
4567         else
4568                 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);
4569         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4570         R_SetViewport(&r_refdef.view.viewport);
4571 }
4572
4573 void R_EntityMatrix(const matrix4x4_t *matrix)
4574 {
4575         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4576         {
4577                 gl_modelmatrixchanged = false;
4578                 gl_modelmatrix = *matrix;
4579                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4580                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4581                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4582                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4583                 CHECKGLERROR
4584                 switch(vid.renderpath)
4585                 {
4586                 case RENDERPATH_GL32:
4587                 case RENDERPATH_GLES2:
4588                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4589                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4590                         break;
4591                 }
4592         }
4593 }
4594
4595 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4596 {
4597         r_viewport_t viewport;
4598
4599         CHECKGLERROR
4600
4601         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4602         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4603         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4604         R_SetViewport(&viewport);
4605         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4606         GL_Color(1, 1, 1, 1);
4607         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4608         GL_BlendFunc(GL_ONE, GL_ZERO);
4609         GL_ScissorTest(false);
4610         GL_DepthMask(false);
4611         GL_DepthRange(0, 1);
4612         GL_DepthTest(false);
4613         GL_DepthFunc(GL_LEQUAL);
4614         R_EntityMatrix(&identitymatrix);
4615         R_Mesh_ResetTextureState();
4616         GL_PolygonOffset(0, 0);
4617         switch(vid.renderpath)
4618         {
4619         case RENDERPATH_GL32:
4620         case RENDERPATH_GLES2:
4621                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4622                 break;
4623         }
4624         GL_CullFace(GL_NONE);
4625
4626         CHECKGLERROR
4627 }
4628
4629 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4630 {
4631         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4632 }
4633
4634 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4635 {
4636         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4637         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4638         GL_Color(1, 1, 1, 1);
4639         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4640         GL_BlendFunc(GL_ONE, GL_ZERO);
4641         GL_ScissorTest(true);
4642         GL_DepthMask(true);
4643         GL_DepthRange(0, 1);
4644         GL_DepthTest(true);
4645         GL_DepthFunc(GL_LEQUAL);
4646         R_EntityMatrix(&identitymatrix);
4647         R_Mesh_ResetTextureState();
4648         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4649         switch(vid.renderpath)
4650         {
4651         case RENDERPATH_GL32:
4652         case RENDERPATH_GLES2:
4653                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4654                 break;
4655         }
4656         GL_CullFace(r_refdef.view.cullface_back);
4657 }
4658
4659 /*
4660 ================
4661 R_RenderView_UpdateViewVectors
4662 ================
4663 */
4664 void R_RenderView_UpdateViewVectors(void)
4665 {
4666         // break apart the view matrix into vectors for various purposes
4667         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4668         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4669         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4670         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4671         // make an inverted copy of the view matrix for tracking sprites
4672         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4673 }
4674
4675 void R_RenderTarget_FreeUnused(qboolean force)
4676 {
4677         unsigned int i, j, end;
4678         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4679         for (i = 0; i < end; i++)
4680         {
4681                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4682                 // free resources for rendertargets that have not been used for a while
4683                 // (note: this check is run after the frame render, so any targets used
4684                 // this frame will not be affected even at low framerates)
4685                 if (r && (realtime - r->lastusetime > 0.2 || force))
4686                 {
4687                         if (r->fbo)
4688                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4689                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4690                                 if (r->colortexture[j])
4691                                         R_FreeTexture(r->colortexture[j]);
4692                         if (r->depthtexture)
4693                                 R_FreeTexture(r->depthtexture);
4694                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4695                 }
4696         }
4697 }
4698
4699 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4700 {
4701         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4702         x1 = x * iw;
4703         x2 = (x + w) * iw;
4704         y1 = (th - y) * ih;
4705         y2 = (th - y - h) * ih;
4706         texcoord2f[0] = x1;
4707         texcoord2f[2] = x2;
4708         texcoord2f[4] = x2;
4709         texcoord2f[6] = x1;
4710         texcoord2f[1] = y1;
4711         texcoord2f[3] = y1;
4712         texcoord2f[5] = y2;
4713         texcoord2f[7] = y2;
4714 }
4715
4716 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)
4717 {
4718         unsigned int i, j, end;
4719         r_rendertarget_t *r = NULL;
4720         char vabuf[256];
4721         // first try to reuse an existing slot if possible
4722         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4723         for (i = 0; i < end; i++)
4724         {
4725                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4726                 if (r && r->lastusetime != 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)
4727                         break;
4728         }
4729         if (i == end)
4730         {
4731                 // no unused exact match found, so we have to make one in the first unused slot
4732                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4733                 r->texturewidth = texturewidth;
4734                 r->textureheight = textureheight;
4735                 r->colortextype[0] = colortextype0;
4736                 r->colortextype[1] = colortextype1;
4737                 r->colortextype[2] = colortextype2;
4738                 r->colortextype[3] = colortextype3;
4739                 r->depthtextype = depthtextype;
4740                 r->depthisrenderbuffer = depthisrenderbuffer;
4741                 for (j = 0; j < 4; j++)
4742                         if (r->colortextype[j])
4743                                 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);
4744                 if (r->depthtextype)
4745                 {
4746                         if (r->depthisrenderbuffer)
4747                                 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);
4748                         else
4749                                 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);
4750                 }
4751                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4752         }
4753         r_refdef.stats[r_stat_rendertargets_used]++;
4754         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4755         r->lastusetime = realtime;
4756         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4757         return r;
4758 }
4759
4760 static void R_Water_StartFrame(int viewwidth, int viewheight)
4761 {
4762         int waterwidth, waterheight;
4763
4764         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4765                 return;
4766
4767         // set waterwidth and waterheight to the water resolution that will be
4768         // used (often less than the screen resolution for faster rendering)
4769         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4770         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4771
4772         if (!r_water.integer || r_showsurfaces.integer)
4773                 waterwidth = waterheight = 0;
4774
4775         // set up variables that will be used in shader setup
4776         r_fb.water.waterwidth = waterwidth;
4777         r_fb.water.waterheight = waterheight;
4778         r_fb.water.texturewidth = waterwidth;
4779         r_fb.water.textureheight = waterheight;
4780         r_fb.water.camerawidth = waterwidth;
4781         r_fb.water.cameraheight = waterheight;
4782         r_fb.water.screenscale[0] = 0.5f;
4783         r_fb.water.screenscale[1] = 0.5f;
4784         r_fb.water.screencenter[0] = 0.5f;
4785         r_fb.water.screencenter[1] = 0.5f;
4786         r_fb.water.enabled = waterwidth != 0;
4787
4788         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4789         r_fb.water.numwaterplanes = 0;
4790 }
4791
4792 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4793 {
4794         int planeindex, bestplaneindex, vertexindex;
4795         vec3_t mins, maxs, normal, center, v, n;
4796         vec_t planescore, bestplanescore;
4797         mplane_t plane;
4798         r_waterstate_waterplane_t *p;
4799         texture_t *t = R_GetCurrentTexture(surface->texture);
4800
4801         rsurface.texture = t;
4802         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4803         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4804         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4805                 return;
4806         // average the vertex normals, find the surface bounds (after deformvertexes)
4807         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4808         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4809         VectorCopy(n, normal);
4810         VectorCopy(v, mins);
4811         VectorCopy(v, maxs);
4812         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4813         {
4814                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4815                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4816                 VectorAdd(normal, n, normal);
4817                 mins[0] = min(mins[0], v[0]);
4818                 mins[1] = min(mins[1], v[1]);
4819                 mins[2] = min(mins[2], v[2]);
4820                 maxs[0] = max(maxs[0], v[0]);
4821                 maxs[1] = max(maxs[1], v[1]);
4822                 maxs[2] = max(maxs[2], v[2]);
4823         }
4824         VectorNormalize(normal);
4825         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4826
4827         VectorCopy(normal, plane.normal);
4828         VectorNormalize(plane.normal);
4829         plane.dist = DotProduct(center, plane.normal);
4830         PlaneClassify(&plane);
4831         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4832         {
4833                 // skip backfaces (except if nocullface is set)
4834 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4835 //                      return;
4836                 VectorNegate(plane.normal, plane.normal);
4837                 plane.dist *= -1;
4838                 PlaneClassify(&plane);
4839         }
4840
4841
4842         // find a matching plane if there is one
4843         bestplaneindex = -1;
4844         bestplanescore = 1048576.0f;
4845         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4846         {
4847                 if(p->camera_entity == t->camera_entity)
4848                 {
4849                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4850                         if (bestplaneindex < 0 || bestplanescore > planescore)
4851                         {
4852                                 bestplaneindex = planeindex;
4853                                 bestplanescore = planescore;
4854                         }
4855                 }
4856         }
4857         planeindex = bestplaneindex;
4858
4859         // if this surface does not fit any known plane rendered this frame, add one
4860         if (planeindex < 0 || bestplanescore > 0.001f)
4861         {
4862                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4863                 {
4864                         // store the new plane
4865                         planeindex = r_fb.water.numwaterplanes++;
4866                         p = r_fb.water.waterplanes + planeindex;
4867                         p->plane = plane;
4868                         // clear materialflags and pvs
4869                         p->materialflags = 0;
4870                         p->pvsvalid = false;
4871                         p->camera_entity = t->camera_entity;
4872                         VectorCopy(mins, p->mins);
4873                         VectorCopy(maxs, p->maxs);
4874                 }
4875                 else
4876                 {
4877                         // We're totally screwed.
4878                         return;
4879                 }
4880         }
4881         else
4882         {
4883                 // merge mins/maxs when we're adding this surface to the plane
4884                 p = r_fb.water.waterplanes + planeindex;
4885                 p->mins[0] = min(p->mins[0], mins[0]);
4886                 p->mins[1] = min(p->mins[1], mins[1]);
4887                 p->mins[2] = min(p->mins[2], mins[2]);
4888                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4889                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4890                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4891         }
4892         // merge this surface's materialflags into the waterplane
4893         p->materialflags |= t->currentmaterialflags;
4894         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4895         {
4896                 // merge this surface's PVS into the waterplane
4897                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4898                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4899                 {
4900                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4901                         p->pvsvalid = true;
4902                 }
4903         }
4904 }
4905
4906 extern cvar_t r_drawparticles;
4907 extern cvar_t r_drawdecals;
4908
4909 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4910 {
4911         int myscissor[4];
4912         r_refdef_view_t originalview;
4913         r_refdef_view_t myview;
4914         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;
4915         r_waterstate_waterplane_t *p;
4916         vec3_t visorigin;
4917         r_rendertarget_t *rt;
4918
4919         originalview = r_refdef.view;
4920
4921         // lowquality hack, temporarily shut down some cvars and restore afterwards
4922         qualityreduction = r_water_lowquality.integer;
4923         if (qualityreduction > 0)
4924         {
4925                 if (qualityreduction >= 1)
4926                 {
4927                         old_r_shadows = r_shadows.integer;
4928                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4929                         old_r_dlight = r_shadow_realtime_dlight.integer;
4930                         Cvar_SetValueQuick(&r_shadows, 0);
4931                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4932                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4933                 }
4934                 if (qualityreduction >= 2)
4935                 {
4936                         old_r_dynamic = r_dynamic.integer;
4937                         old_r_particles = r_drawparticles.integer;
4938                         old_r_decals = r_drawdecals.integer;
4939                         Cvar_SetValueQuick(&r_dynamic, 0);
4940                         Cvar_SetValueQuick(&r_drawparticles, 0);
4941                         Cvar_SetValueQuick(&r_drawdecals, 0);
4942                 }
4943         }
4944
4945         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4946         {
4947                 p->rt_reflection = NULL;
4948                 p->rt_refraction = NULL;
4949                 p->rt_camera = NULL;
4950         }
4951
4952         // render views
4953         r_refdef.view = originalview;
4954         r_refdef.view.showdebug = false;
4955         r_refdef.view.width = r_fb.water.waterwidth;
4956         r_refdef.view.height = r_fb.water.waterheight;
4957         r_refdef.view.useclipplane = true;
4958         myview = r_refdef.view;
4959         r_fb.water.renderingscene = true;
4960         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4961         {
4962                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4963                         continue;
4964
4965                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4966                 {
4967                         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);
4968                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4969                                 goto error;
4970                         r_refdef.view = myview;
4971                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4972                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4973                         if(r_water_scissormode.integer)
4974                         {
4975                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4976                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4977                                 {
4978                                         p->rt_reflection = NULL;
4979                                         p->rt_refraction = NULL;
4980                                         p->rt_camera = NULL;
4981                                         continue;
4982                                 }
4983                         }
4984
4985                         r_refdef.view.clipplane = p->plane;
4986                         // reflected view origin may be in solid, so don't cull with it
4987                         r_refdef.view.usevieworiginculling = false;
4988                         // reverse the cullface settings for this render
4989                         r_refdef.view.cullface_front = GL_FRONT;
4990                         r_refdef.view.cullface_back = GL_BACK;
4991                         // combined pvs (based on what can be seen from each surface center)
4992                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4993                         {
4994                                 r_refdef.view.usecustompvs = true;
4995                                 if (p->pvsvalid)
4996                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4997                                 else
4998                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4999                         }
5000
5001                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
5002                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5003                         GL_ScissorTest(false);
5004                         R_ClearScreen(r_refdef.fogenabled);
5005                         GL_ScissorTest(true);
5006                         if(r_water_scissormode.integer & 2)
5007                                 R_View_UpdateWithScissor(myscissor);
5008                         else
5009                                 R_View_Update();
5010                         R_AnimCache_CacheVisibleEntities();
5011                         if(r_water_scissormode.integer & 1)
5012                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5013                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5014
5015                         r_fb.water.hideplayer = false;
5016                         p->rt_reflection = rt;
5017                 }
5018
5019                 // render the normal view scene and copy into texture
5020                 // (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)
5021                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5022                 {
5023                         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);
5024                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5025                                 goto error;
5026                         r_refdef.view = myview;
5027                         if(r_water_scissormode.integer)
5028                         {
5029                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5030                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5031                                 {
5032                                         p->rt_reflection = NULL;
5033                                         p->rt_refraction = NULL;
5034                                         p->rt_camera = NULL;
5035                                         continue;
5036                                 }
5037                         }
5038
5039                         // combined pvs (based on what can be seen from each surface center)
5040                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
5041                         {
5042                                 r_refdef.view.usecustompvs = true;
5043                                 if (p->pvsvalid)
5044                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5045                                 else
5046                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5047                         }
5048
5049                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5050
5051                         r_refdef.view.clipplane = p->plane;
5052                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5053                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5054
5055                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5056                         {
5057                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5058                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5059                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5060                                 R_RenderView_UpdateViewVectors();
5061                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5062                                 {
5063                                         r_refdef.view.usecustompvs = true;
5064                                         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);
5065                                 }
5066                         }
5067
5068                         PlaneClassify(&r_refdef.view.clipplane);
5069
5070                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5071                         GL_ScissorTest(false);
5072                         R_ClearScreen(r_refdef.fogenabled);
5073                         GL_ScissorTest(true);
5074                         if(r_water_scissormode.integer & 2)
5075                                 R_View_UpdateWithScissor(myscissor);
5076                         else
5077                                 R_View_Update();
5078                         R_AnimCache_CacheVisibleEntities();
5079                         if(r_water_scissormode.integer & 1)
5080                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5081                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5082
5083                         r_fb.water.hideplayer = false;
5084                         p->rt_refraction = rt;
5085                 }
5086                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5087                 {
5088                         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);
5089                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5090                                 goto error;
5091                         r_refdef.view = myview;
5092
5093                         r_refdef.view.clipplane = p->plane;
5094                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5095                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5096
5097                         r_refdef.view.width = r_fb.water.camerawidth;
5098                         r_refdef.view.height = r_fb.water.cameraheight;
5099                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5100                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5101                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5102                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5103
5104                         if(p->camera_entity)
5105                         {
5106                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5107                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5108                         }
5109
5110                         // note: all of the view is used for displaying... so
5111                         // there is no use in scissoring
5112
5113                         // reverse the cullface settings for this render
5114                         r_refdef.view.cullface_front = GL_FRONT;
5115                         r_refdef.view.cullface_back = GL_BACK;
5116                         // also reverse the view matrix
5117                         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
5118                         R_RenderView_UpdateViewVectors();
5119                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5120                         {
5121                                 r_refdef.view.usecustompvs = true;
5122                                 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);
5123                         }
5124                         
5125                         // camera needs no clipplane
5126                         r_refdef.view.useclipplane = false;
5127                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5128                         r_refdef.view.usevieworiginculling = false;
5129
5130                         PlaneClassify(&r_refdef.view.clipplane);
5131
5132                         r_fb.water.hideplayer = false;
5133
5134                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5135                         GL_ScissorTest(false);
5136                         R_ClearScreen(r_refdef.fogenabled);
5137                         GL_ScissorTest(true);
5138                         R_View_Update();
5139                         R_AnimCache_CacheVisibleEntities();
5140                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5141
5142                         r_fb.water.hideplayer = false;
5143                         p->rt_camera = rt;
5144                 }
5145
5146         }
5147         r_fb.water.renderingscene = false;
5148         r_refdef.view = originalview;
5149         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5150         R_View_Update();
5151         R_AnimCache_CacheVisibleEntities();
5152         goto finish;
5153 error:
5154         r_refdef.view = originalview;
5155         r_fb.water.renderingscene = false;
5156         Cvar_SetValueQuick(&r_water, 0);
5157         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5158 finish:
5159         // lowquality hack, restore cvars
5160         if (qualityreduction > 0)
5161         {
5162                 if (qualityreduction >= 1)
5163                 {
5164                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5165                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5166                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5167                 }
5168                 if (qualityreduction >= 2)
5169                 {
5170                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5171                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5172                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5173                 }
5174         }
5175 }
5176
5177 static void R_Bloom_StartFrame(void)
5178 {
5179         int screentexturewidth, screentextureheight;
5180         textype_t textype = TEXTYPE_COLORBUFFER;
5181         double scale;
5182
5183         // clear the pointers to rendertargets from last frame as they're stale
5184         r_fb.rt_screen = NULL;
5185         r_fb.rt_bloom = NULL;
5186
5187         switch (vid.renderpath)
5188         {
5189         case RENDERPATH_GL32:
5190                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5191                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5192                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5193                 break;
5194         case RENDERPATH_GLES2:
5195                 r_fb.usedepthtextures = false;
5196                 break;
5197         }
5198
5199         if (r_viewscale_fpsscaling.integer)
5200         {
5201                 double actualframetime;
5202                 double targetframetime;
5203                 double adjust;
5204                 actualframetime = r_refdef.lastdrawscreentime;
5205                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5206                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5207                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5208                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5209                 {
5210                         if (adjust > 0)
5211                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5212                         else
5213                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5214                 }
5215                 viewscalefpsadjusted += adjust;
5216                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5217         }
5218         else
5219                 viewscalefpsadjusted = 1.0f;
5220
5221         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5222         if (vid.samples)
5223                 scale *= sqrt(vid.samples); // supersampling
5224         scale = bound(0.03125f, scale, 4.0f);
5225         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5226         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5227         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5228         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5229
5230         // set bloomwidth and bloomheight to the bloom resolution that will be
5231         // used (often less than the screen resolution for faster rendering)
5232         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5233         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5234         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5235         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5236         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5237
5238         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))
5239         {
5240                 Cvar_SetValueQuick(&r_bloom, 0);
5241                 Cvar_SetValueQuick(&r_motionblur, 0);
5242                 Cvar_SetValueQuick(&r_damageblur, 0);
5243         }
5244         if (!r_bloom.integer)
5245                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5246
5247         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5248         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5249         {
5250                 if (r_fb.ghosttexture)
5251                         R_FreeTexture(r_fb.ghosttexture);
5252                 r_fb.ghosttexture = NULL;
5253
5254                 r_fb.screentexturewidth = screentexturewidth;
5255                 r_fb.screentextureheight = screentextureheight;
5256                 r_fb.textype = textype;
5257
5258                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5259                 {
5260                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5261                                 r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_CLAMP, -1, NULL);
5262                         r_fb.ghosttexture_valid = false;
5263                 }
5264         }
5265
5266         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5267
5268         r_refdef.view.clear = true;
5269 }
5270
5271 static void R_Bloom_MakeTexture(void)
5272 {
5273         int x, range, dir;
5274         float xoffset, yoffset, r, brighten;
5275         float colorscale = r_bloom_colorscale.value;
5276         r_viewport_t bloomviewport;
5277         r_rendertarget_t *prev, *cur;
5278         textype_t textype = r_fb.rt_screen->colortextype[0];
5279
5280         r_refdef.stats[r_stat_bloom]++;
5281
5282         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5283
5284         // scale down screen texture to the bloom texture size
5285         CHECKGLERROR
5286         prev = r_fb.rt_screen;
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         R_SetViewport(&bloomviewport);
5290         GL_CullFace(GL_NONE);
5291         GL_DepthTest(false);
5292         GL_BlendFunc(GL_ONE, GL_ZERO);
5293         GL_Color(colorscale, colorscale, colorscale, 1);
5294         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5295         // TODO: do boxfilter scale-down in shader?
5296         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5297         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5298         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5299         // we now have a properly scaled bloom image
5300
5301         // multiply bloom image by itself as many times as desired to darken it
5302         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5303         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5304         {
5305                 prev = cur;
5306                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5307                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5308                 x *= 2;
5309                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5310                 if(x <= 2)
5311                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5312                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5313                 GL_Color(1,1,1,1); // no fix factor supported here
5314                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5315                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5316                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5317                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5318         }
5319         CHECKGLERROR
5320
5321         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5322         brighten = r_bloom_brighten.value;
5323         brighten = sqrt(brighten);
5324         if(range >= 1)
5325                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5326
5327         for (dir = 0;dir < 2;dir++)
5328         {
5329                 prev = cur;
5330                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5331                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5332                 // blend on at multiple vertical offsets to achieve a vertical blur
5333                 // TODO: do offset blends using GLSL
5334                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5335                 CHECKGLERROR
5336                 GL_BlendFunc(GL_ONE, GL_ZERO);
5337                 CHECKGLERROR
5338                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5339                 CHECKGLERROR
5340                 for (x = -range;x <= range;x++)
5341                 {
5342                         if (!dir){xoffset = 0;yoffset = x;}
5343                         else {xoffset = x;yoffset = 0;}
5344                         xoffset /= (float)prev->texturewidth;
5345                         yoffset /= (float)prev->textureheight;
5346                         // compute a texcoord array with the specified x and y offset
5347                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5348                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5349                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5350                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5351                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5352                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5353                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5354                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5355                         // this r value looks like a 'dot' particle, fading sharply to
5356                         // black at the edges
5357                         // (probably not realistic but looks good enough)
5358                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5359                         //r = brighten/(range*2+1);
5360                         r = brighten / (range * 2 + 1);
5361                         if(range >= 1)
5362                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5363                         if (r <= 0)
5364                                 continue;
5365                         CHECKGLERROR
5366                         GL_Color(r, r, r, 1);
5367                         CHECKGLERROR
5368                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5369                         CHECKGLERROR
5370                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5371                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5372                         CHECKGLERROR
5373                         GL_BlendFunc(GL_ONE, GL_ONE);
5374                         CHECKGLERROR
5375                 }
5376         }
5377
5378         // now we have the bloom image, so keep track of it
5379         r_fb.rt_bloom = cur;
5380 }
5381
5382 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5383 {
5384         dpuint64 permutation;
5385         float uservecs[4][4];
5386         rtexture_t *viewtexture;
5387         rtexture_t *bloomtexture;
5388
5389         R_EntityMatrix(&identitymatrix);
5390
5391         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5392         {
5393                 // declare variables
5394                 float blur_factor, blur_mouseaccel, blur_velocity;
5395                 static float blur_average; 
5396                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5397
5398                 // set a goal for the factoring
5399                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5400                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5401                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5402                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5403                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5404                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5405
5406                 // from the goal, pick an averaged value between goal and last value
5407                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5408                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5409
5410                 // enforce minimum amount of blur 
5411                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5412
5413                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5414
5415                 // calculate values into a standard alpha
5416                 cl.motionbluralpha = 1 - exp(-
5417                                 (
5418                                         (r_motionblur.value * blur_factor / 80)
5419                                         +
5420                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5421                                 )
5422                                 /
5423                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5424                                 );
5425
5426                 // randomization for the blur value to combat persistent ghosting
5427                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5428                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5429
5430                 // apply the blur
5431                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5432                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5433                 {
5434                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5435                         GL_Color(1, 1, 1, cl.motionbluralpha);
5436                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5437                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5438                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5439                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5440                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5441                 }
5442
5443                 // updates old view angles for next pass
5444                 VectorCopy(cl.viewangles, blur_oldangles);
5445
5446                 // copy view into the ghost texture
5447                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5448                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5449                 r_fb.ghosttexture_valid = true;
5450         }
5451
5452         if (r_fb.bloomwidth)
5453         {
5454                 // make the bloom texture
5455                 R_Bloom_MakeTexture();
5456         }
5457
5458 #if _MSC_VER >= 1400
5459 #define sscanf sscanf_s
5460 #endif
5461         memset(uservecs, 0, sizeof(uservecs));
5462         if (r_glsl_postprocess_uservec1_enable.integer)
5463                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5464         if (r_glsl_postprocess_uservec2_enable.integer)
5465                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5466         if (r_glsl_postprocess_uservec3_enable.integer)
5467                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5468         if (r_glsl_postprocess_uservec4_enable.integer)
5469                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5470
5471         // render to the screen fbo
5472         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5473         GL_Color(1, 1, 1, 1);
5474         GL_BlendFunc(GL_ONE, GL_ZERO);
5475
5476         viewtexture = r_fb.rt_screen->colortexture[0];
5477         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5478
5479         if (r_rendertarget_debug.integer >= 0)
5480         {
5481                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5482                 if (rt && rt->colortexture[0])
5483                 {
5484                         viewtexture = rt->colortexture[0];
5485                         bloomtexture = NULL;
5486                 }
5487         }
5488
5489         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5490         switch(vid.renderpath)
5491         {
5492         case RENDERPATH_GL32:
5493         case RENDERPATH_GLES2:
5494                 permutation =
5495                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5496                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5497                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5498                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5499                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5500                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5501                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5502                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5503                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5504                 if (r_glsl_permutation->tex_Texture_LUT             >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LUT,        r_texture_lut       );
5505                 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]);
5506                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5507                 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]);
5508                 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]);
5509                 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]);
5510                 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]);
5511                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5512                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5513                 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);
5514                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5515                 break;
5516         }
5517         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5518         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5519 }
5520
5521 matrix4x4_t r_waterscrollmatrix;
5522
5523 void R_UpdateFog(void)
5524 {
5525         // Nehahra fog
5526         if (gamemode == GAME_NEHAHRA)
5527         {
5528                 if (gl_fogenable.integer)
5529                 {
5530                         r_refdef.oldgl_fogenable = true;
5531                         r_refdef.fog_density = gl_fogdensity.value;
5532                         r_refdef.fog_red = gl_fogred.value;
5533                         r_refdef.fog_green = gl_foggreen.value;
5534                         r_refdef.fog_blue = gl_fogblue.value;
5535                         r_refdef.fog_alpha = 1;
5536                         r_refdef.fog_start = 0;
5537                         r_refdef.fog_end = gl_skyclip.value;
5538                         r_refdef.fog_height = 1<<30;
5539                         r_refdef.fog_fadedepth = 128;
5540                 }
5541                 else if (r_refdef.oldgl_fogenable)
5542                 {
5543                         r_refdef.oldgl_fogenable = false;
5544                         r_refdef.fog_density = 0;
5545                         r_refdef.fog_red = 0;
5546                         r_refdef.fog_green = 0;
5547                         r_refdef.fog_blue = 0;
5548                         r_refdef.fog_alpha = 0;
5549                         r_refdef.fog_start = 0;
5550                         r_refdef.fog_end = 0;
5551                         r_refdef.fog_height = 1<<30;
5552                         r_refdef.fog_fadedepth = 128;
5553                 }
5554         }
5555
5556         // fog parms
5557         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5558         r_refdef.fog_start = max(0, r_refdef.fog_start);
5559         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5560
5561         if (r_refdef.fog_density && r_drawfog.integer)
5562         {
5563                 r_refdef.fogenabled = true;
5564                 // this is the point where the fog reaches 0.9986 alpha, which we
5565                 // consider a good enough cutoff point for the texture
5566                 // (0.9986 * 256 == 255.6)
5567                 if (r_fog_exp2.integer)
5568                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5569                 else
5570                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5571                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5572                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5573                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5574                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5575                         R_BuildFogHeightTexture();
5576                 // fog color was already set
5577                 // update the fog texture
5578                 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)
5579                         R_BuildFogTexture();
5580                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5581                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5582         }
5583         else
5584                 r_refdef.fogenabled = false;
5585
5586         // fog color
5587         if (r_refdef.fog_density)
5588         {
5589                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5590                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5591                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5592
5593                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5594                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5595                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5596                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5597
5598                 {
5599                         vec3_t fogvec;
5600                         VectorCopy(r_refdef.fogcolor, fogvec);
5601                         //   color.rgb *= ContrastBoost * SceneBrightness;
5602                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5603                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5604                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5605                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5606                 }
5607         }
5608 }
5609
5610 void R_UpdateVariables(void)
5611 {
5612         R_Textures_Frame();
5613
5614         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5615
5616         r_refdef.farclip = r_farclip_base.value;
5617         if (r_refdef.scene.worldmodel)
5618                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5619         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5620
5621         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5622                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5623         r_refdef.polygonfactor = 0;
5624         r_refdef.polygonoffset = 0;
5625
5626         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5627         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5628         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5629         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5630         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5631         if (r_refdef.scene.worldmodel)
5632         {
5633                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5634         }
5635         if (r_showsurfaces.integer)
5636         {
5637                 r_refdef.scene.rtworld = false;
5638                 r_refdef.scene.rtworldshadows = false;
5639                 r_refdef.scene.rtdlight = false;
5640                 r_refdef.scene.rtdlightshadows = false;
5641                 r_refdef.scene.lightmapintensity = 0;
5642         }
5643
5644         r_gpuskeletal = false;
5645         switch(vid.renderpath)
5646         {
5647         case RENDERPATH_GL32:
5648                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5649         case RENDERPATH_GLES2:
5650                 if (r_glsl_postprocess.integer)
5651                 {
5652                         if (r_glsl_postprocess_color_lut.string[0])
5653                         {
5654                                 r_texture_lut_pic = Draw_CachePic_Flags(r_glsl_postprocess_color_lut.string, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_LINEAR);
5655                                 if (r_texture_lut_pic)
5656                                         r_texture_lut = Draw_GetPicTexture(r_texture_lut_pic);
5657                                 else
5658                                         r_texture_lut = r_texture_lut_default;
5659                         }
5660                         else
5661                         {
5662                                 r_texture_lut = r_texture_lut_default;
5663                         }
5664                 }
5665                 if(!vid_gammatables_trivial)
5666                 {
5667                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5668                         {
5669                                 // build GLSL gamma texture
5670 #define RAMPWIDTH 256
5671                                 unsigned short ramp[RAMPWIDTH * 3];
5672                                 unsigned char rampbgr[RAMPWIDTH][4];
5673                                 int i;
5674
5675                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5676
5677                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5678                                 for(i = 0; i < RAMPWIDTH; ++i)
5679                                 {
5680                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5681                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5682                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5683                                         rampbgr[i][3] = 0;
5684                                 }
5685                                 if (r_texture_gammaramps)
5686                                 {
5687                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5688                                 }
5689                                 else
5690                                 {
5691                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5692                                 }
5693                         }
5694                 }
5695                 else
5696                 {
5697                         // remove GLSL gamma texture
5698                 }
5699                 break;
5700         }
5701 }
5702
5703 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5704 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5705 /*
5706 ================
5707 R_SelectScene
5708 ================
5709 */
5710 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5711         if( scenetype != r_currentscenetype ) {
5712                 // store the old scenetype
5713                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5714                 r_currentscenetype = scenetype;
5715                 // move in the new scene
5716                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5717         }
5718 }
5719
5720 /*
5721 ================
5722 R_GetScenePointer
5723 ================
5724 */
5725 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5726 {
5727         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5728         if( scenetype == r_currentscenetype ) {
5729                 return &r_refdef.scene;
5730         } else {
5731                 return &r_scenes_store[ scenetype ];
5732         }
5733 }
5734
5735 static int R_SortEntities_Compare(const void *ap, const void *bp)
5736 {
5737         const entity_render_t *a = *(const entity_render_t **)ap;
5738         const entity_render_t *b = *(const entity_render_t **)bp;
5739
5740         // 1. compare model
5741         if(a->model < b->model)
5742                 return -1;
5743         if(a->model > b->model)
5744                 return +1;
5745
5746         // 2. compare skin
5747         // TODO possibly calculate the REAL skinnum here first using
5748         // skinscenes?
5749         if(a->skinnum < b->skinnum)
5750                 return -1;
5751         if(a->skinnum > b->skinnum)
5752                 return +1;
5753
5754         // everything we compared is equal
5755         return 0;
5756 }
5757 static void R_SortEntities(void)
5758 {
5759         // below or equal 2 ents, sorting never gains anything
5760         if(r_refdef.scene.numentities <= 2)
5761                 return;
5762         // sort
5763         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5764 }
5765
5766 /*
5767 ================
5768 R_RenderView
5769 ================
5770 */
5771 extern cvar_t r_shadow_bouncegrid;
5772 extern cvar_t v_isometric;
5773 extern void V_MakeViewIsometric(void);
5774 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5775 {
5776         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5777         int viewfbo = 0;
5778         rtexture_t *viewdepthtexture = NULL;
5779         rtexture_t *viewcolortexture = NULL;
5780         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5781
5782         // finish any 2D rendering that was queued
5783         DrawQ_Finish();
5784
5785         if (r_timereport_active)
5786                 R_TimeReport("start");
5787         r_textureframe++; // used only by R_GetCurrentTexture
5788         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5789
5790         if(R_CompileShader_CheckStaticParms())
5791                 R_GLSL_Restart_f(&cmd_client);
5792
5793         if (!r_drawentities.integer)
5794                 r_refdef.scene.numentities = 0;
5795         else if (r_sortentities.integer)
5796                 R_SortEntities();
5797
5798         R_AnimCache_ClearCache();
5799
5800         /* adjust for stereo display */
5801         if(R_Stereo_Active())
5802         {
5803                 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);
5804                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5805         }
5806
5807         if (r_refdef.view.isoverlay)
5808         {
5809                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5810                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5811                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5812                 R_TimeReport("depthclear");
5813
5814                 r_refdef.view.showdebug = false;
5815
5816                 r_fb.water.enabled = false;
5817                 r_fb.water.numwaterplanes = 0;
5818
5819                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5820
5821                 r_refdef.view.matrix = originalmatrix;
5822
5823                 CHECKGLERROR
5824                 return;
5825         }
5826
5827         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5828         {
5829                 r_refdef.view.matrix = originalmatrix;
5830                 return;
5831         }
5832
5833         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5834         if (v_isometric.integer && r_refdef.view.ismain)
5835                 V_MakeViewIsometric();
5836
5837         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5838
5839         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5840                 // in sRGB fallback, behave similar to true sRGB: convert this
5841                 // value from linear to sRGB
5842                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5843
5844         R_RenderView_UpdateViewVectors();
5845
5846         R_Shadow_UpdateWorldLightSelection();
5847
5848         // this will set up r_fb.rt_screen
5849         R_Bloom_StartFrame();
5850
5851         // apply bloom brightness offset
5852         if(r_fb.rt_bloom)
5853                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5854
5855         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5856         if (r_fb.rt_screen)
5857         {
5858                 viewfbo = r_fb.rt_screen->fbo;
5859                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5860                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5861                 viewx = 0;
5862                 viewy = 0;
5863                 viewwidth = r_fb.rt_screen->texturewidth;
5864                 viewheight = r_fb.rt_screen->textureheight;
5865         }
5866
5867         R_Water_StartFrame(viewwidth, viewheight);
5868
5869         CHECKGLERROR
5870         if (r_timereport_active)
5871                 R_TimeReport("viewsetup");
5872
5873         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5874
5875         // clear the whole fbo every frame - otherwise the driver will consider
5876         // it to be an inter-frame texture and stall in multi-gpu configurations
5877         if (r_fb.rt_screen)
5878                 GL_ScissorTest(false);
5879         R_ClearScreen(r_refdef.fogenabled);
5880         if (r_timereport_active)
5881                 R_TimeReport("viewclear");
5882
5883         r_refdef.view.clear = true;
5884
5885         r_refdef.view.showdebug = true;
5886
5887         R_View_Update();
5888         if (r_timereport_active)
5889                 R_TimeReport("visibility");
5890
5891         R_AnimCache_CacheVisibleEntities();
5892         if (r_timereport_active)
5893                 R_TimeReport("animcache");
5894
5895         R_Shadow_UpdateBounceGridTexture();
5896         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5897
5898         r_fb.water.numwaterplanes = 0;
5899         if (r_fb.water.enabled)
5900                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5901
5902         // for the actual view render we use scissoring a fair amount, so scissor
5903         // test needs to be on
5904         if (r_fb.rt_screen)
5905                 GL_ScissorTest(true);
5906         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5907         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5908         r_fb.water.numwaterplanes = 0;
5909
5910         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5911         GL_ScissorTest(false);
5912
5913         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5914         if (r_timereport_active)
5915                 R_TimeReport("blendview");
5916
5917         r_refdef.view.matrix = originalmatrix;
5918
5919         CHECKGLERROR
5920
5921         // go back to 2d rendering
5922         DrawQ_Start();
5923 }
5924
5925 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5926 {
5927         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5928         {
5929                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5930                 if (r_timereport_active)
5931                         R_TimeReport("waterworld");
5932         }
5933
5934         // don't let sound skip if going slow
5935         if (r_refdef.scene.extraupdate)
5936                 S_ExtraUpdate ();
5937
5938         R_DrawModelsAddWaterPlanes();
5939         if (r_timereport_active)
5940                 R_TimeReport("watermodels");
5941
5942         if (r_fb.water.numwaterplanes)
5943         {
5944                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5945                 if (r_timereport_active)
5946                         R_TimeReport("waterscenes");
5947         }
5948 }
5949
5950 extern cvar_t cl_locs_show;
5951 static void R_DrawLocs(void);
5952 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5953 static void R_DrawModelDecals(void);
5954 extern qboolean r_shadow_usingdeferredprepass;
5955 extern int r_shadow_shadowmapatlas_modelshadows_size;
5956 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5957 {
5958         qboolean shadowmapping = false;
5959
5960         if (r_timereport_active)
5961                 R_TimeReport("beginscene");
5962
5963         r_refdef.stats[r_stat_renders]++;
5964
5965         R_UpdateFog();
5966
5967         // don't let sound skip if going slow
5968         if (r_refdef.scene.extraupdate)
5969                 S_ExtraUpdate ();
5970
5971         R_MeshQueue_BeginScene();
5972
5973         R_SkyStartFrame();
5974
5975         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);
5976
5977         if (r_timereport_active)
5978                 R_TimeReport("skystartframe");
5979
5980         if (cl.csqc_vidvars.drawworld)
5981         {
5982                 // don't let sound skip if going slow
5983                 if (r_refdef.scene.extraupdate)
5984                         S_ExtraUpdate ();
5985
5986                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5987                 {
5988                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5989                         if (r_timereport_active)
5990                                 R_TimeReport("worldsky");
5991                 }
5992
5993                 if (R_DrawBrushModelsSky() && r_timereport_active)
5994                         R_TimeReport("bmodelsky");
5995
5996                 if (skyrendermasked && skyrenderlater)
5997                 {
5998                         // we have to force off the water clipping plane while rendering sky
5999                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6000                         R_Sky();
6001                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6002                         if (r_timereport_active)
6003                                 R_TimeReport("sky");
6004                 }
6005         }
6006
6007         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
6008         r_shadow_viewfbo = viewfbo;
6009         r_shadow_viewdepthtexture = viewdepthtexture;
6010         r_shadow_viewcolortexture = viewcolortexture;
6011         r_shadow_viewx = viewx;
6012         r_shadow_viewy = viewy;
6013         r_shadow_viewwidth = viewwidth;
6014         r_shadow_viewheight = viewheight;
6015
6016         R_Shadow_PrepareModelShadows();
6017         R_Shadow_PrepareLights();
6018         if (r_timereport_active)
6019                 R_TimeReport("preparelights");
6020
6021         // render all the shadowmaps that will be used for this view
6022         shadowmapping = R_Shadow_ShadowMappingEnabled();
6023         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
6024         {
6025                 R_Shadow_DrawShadowMaps();
6026                 if (r_timereport_active)
6027                         R_TimeReport("shadowmaps");
6028         }
6029
6030         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6031         if (r_shadow_usingdeferredprepass)
6032                 R_Shadow_DrawPrepass();
6033
6034         // now we begin the forward pass of the view render
6035         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6036         {
6037                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6038                 if (r_timereport_active)
6039                         R_TimeReport("worlddepth");
6040         }
6041         if (r_depthfirst.integer >= 2)
6042         {
6043                 R_DrawModelsDepth();
6044                 if (r_timereport_active)
6045                         R_TimeReport("modeldepth");
6046         }
6047
6048         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6049         {
6050                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6051                 if (r_timereport_active)
6052                         R_TimeReport("world");
6053         }
6054
6055         // don't let sound skip if going slow
6056         if (r_refdef.scene.extraupdate)
6057                 S_ExtraUpdate ();
6058
6059         R_DrawModels();
6060         if (r_timereport_active)
6061                 R_TimeReport("models");
6062
6063         // don't let sound skip if going slow
6064         if (r_refdef.scene.extraupdate)
6065                 S_ExtraUpdate ();
6066
6067         if (!r_shadow_usingdeferredprepass)
6068         {
6069                 R_Shadow_DrawLights();
6070                 if (r_timereport_active)
6071                         R_TimeReport("rtlights");
6072         }
6073
6074         // don't let sound skip if going slow
6075         if (r_refdef.scene.extraupdate)
6076                 S_ExtraUpdate ();
6077
6078         if (cl.csqc_vidvars.drawworld)
6079         {
6080                 R_DrawModelDecals();
6081                 if (r_timereport_active)
6082                         R_TimeReport("modeldecals");
6083
6084                 R_DrawParticles();
6085                 if (r_timereport_active)
6086                         R_TimeReport("particles");
6087
6088                 R_DrawExplosions();
6089                 if (r_timereport_active)
6090                         R_TimeReport("explosions");
6091         }
6092
6093         if (r_refdef.view.showdebug)
6094         {
6095                 if (cl_locs_show.integer)
6096                 {
6097                         R_DrawLocs();
6098                         if (r_timereport_active)
6099                                 R_TimeReport("showlocs");
6100                 }
6101
6102                 if (r_drawportals.integer)
6103                 {
6104                         R_DrawPortals();
6105                         if (r_timereport_active)
6106                                 R_TimeReport("portals");
6107                 }
6108
6109                 if (r_showbboxes_client.value > 0)
6110                 {
6111                         R_DrawEntityBBoxes(CLVM_prog);
6112                         if (r_timereport_active)
6113                                 R_TimeReport("clbboxes");
6114                 }
6115                 if (r_showbboxes.value > 0)
6116                 {
6117                         R_DrawEntityBBoxes(SVVM_prog);
6118                         if (r_timereport_active)
6119                                 R_TimeReport("svbboxes");
6120                 }
6121         }
6122
6123         if (r_transparent.integer)
6124         {
6125                 R_MeshQueue_RenderTransparent();
6126                 if (r_timereport_active)
6127                         R_TimeReport("drawtrans");
6128         }
6129
6130         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))
6131         {
6132                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6133                 if (r_timereport_active)
6134                         R_TimeReport("worlddebug");
6135                 R_DrawModelsDebug();
6136                 if (r_timereport_active)
6137                         R_TimeReport("modeldebug");
6138         }
6139
6140         if (cl.csqc_vidvars.drawworld)
6141         {
6142                 R_Shadow_DrawCoronas();
6143                 if (r_timereport_active)
6144                         R_TimeReport("coronas");
6145         }
6146
6147         // don't let sound skip if going slow
6148         if (r_refdef.scene.extraupdate)
6149                 S_ExtraUpdate ();
6150 }
6151
6152 static const unsigned short bboxelements[36] =
6153 {
6154         5, 1, 3, 5, 3, 7,
6155         6, 2, 0, 6, 0, 4,
6156         7, 3, 2, 7, 2, 6,
6157         4, 0, 1, 4, 1, 5,
6158         4, 5, 7, 4, 7, 6,
6159         1, 0, 2, 1, 2, 3,
6160 };
6161
6162 #define BBOXEDGES 13
6163 static const float bboxedges[BBOXEDGES][6] = 
6164 {
6165         // whole box
6166         { 0, 0, 0, 1, 1, 1 },
6167         // bottom edges
6168         { 0, 0, 0, 0, 1, 0 },
6169         { 0, 0, 0, 1, 0, 0 },
6170         { 0, 1, 0, 1, 1, 0 },
6171         { 1, 0, 0, 1, 1, 0 },
6172         // top edges
6173         { 0, 0, 1, 0, 1, 1 },
6174         { 0, 0, 1, 1, 0, 1 },
6175         { 0, 1, 1, 1, 1, 1 },
6176         { 1, 0, 1, 1, 1, 1 },
6177         // vertical edges
6178         { 0, 0, 0, 0, 0, 1 },
6179         { 1, 0, 0, 1, 0, 1 },
6180         { 0, 1, 0, 0, 1, 1 },
6181         { 1, 1, 0, 1, 1, 1 },
6182 };
6183
6184 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6185 {
6186         int numvertices = BBOXEDGES * 8;
6187         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6188         int numtriangles = BBOXEDGES * 12;
6189         unsigned short elements[BBOXEDGES * 36];
6190         int i, edge;
6191         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6192
6193         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6194
6195         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6196         GL_DepthMask(false);
6197         GL_DepthRange(0, 1);
6198         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6199
6200         for (edge = 0; edge < BBOXEDGES; edge++)
6201         {
6202                 for (i = 0; i < 3; i++)
6203                 {
6204                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6205                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6206                 }
6207                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6208                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6209                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6210                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6211                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6212                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6213                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6214                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6215                 for (i = 0; i < 36; i++)
6216                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6217         }
6218         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6219         if (r_refdef.fogenabled)
6220         {
6221                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6222                 {
6223                         f1 = RSurf_FogVertex(v);
6224                         f2 = 1 - f1;
6225                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6226                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6227                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6228                 }
6229         }
6230         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6231         R_Mesh_ResetTextureState();
6232         R_SetupShader_Generic_NoTexture(false, false);
6233         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6234 }
6235
6236 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6237 {
6238         // hacky overloading of the parameters
6239         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6240         int i;
6241         float color[4];
6242         prvm_edict_t *edict;
6243
6244         GL_CullFace(GL_NONE);
6245         R_SetupShader_Generic_NoTexture(false, false);
6246
6247         for (i = 0;i < numsurfaces;i++)
6248         {
6249                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6250                 switch ((int)PRVM_serveredictfloat(edict, solid))
6251                 {
6252                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6253                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6254                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6255                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6256                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6257                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6258                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6259                 }
6260                 if (prog == CLVM_prog)
6261                         color[3] *= r_showbboxes_client.value;
6262                 else
6263                         color[3] *= r_showbboxes.value;
6264                 color[3] = bound(0, color[3], 1);
6265                 GL_DepthTest(!r_showdisabledepthtest.integer);
6266                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6267         }
6268 }
6269
6270 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6271 {
6272         int i;
6273         prvm_edict_t *edict;
6274         vec3_t center;
6275
6276         if (prog == NULL)
6277                 return;
6278
6279         for (i = 0; i < prog->num_edicts; i++)
6280         {
6281                 edict = PRVM_EDICT_NUM(i);
6282                 if (edict->priv.server->free)
6283                         continue;
6284                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6285                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6286                         continue;
6287                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6288                         continue;
6289                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6290                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6291         }
6292 }
6293
6294 static const int nomodelelement3i[24] =
6295 {
6296         5, 2, 0,
6297         5, 1, 2,
6298         5, 0, 3,
6299         5, 3, 1,
6300         0, 2, 4,
6301         2, 1, 4,
6302         3, 0, 4,
6303         1, 3, 4
6304 };
6305
6306 static const unsigned short nomodelelement3s[24] =
6307 {
6308         5, 2, 0,
6309         5, 1, 2,
6310         5, 0, 3,
6311         5, 3, 1,
6312         0, 2, 4,
6313         2, 1, 4,
6314         3, 0, 4,
6315         1, 3, 4
6316 };
6317
6318 static const float nomodelvertex3f[6*3] =
6319 {
6320         -16,   0,   0,
6321          16,   0,   0,
6322           0, -16,   0,
6323           0,  16,   0,
6324           0,   0, -16,
6325           0,   0,  16
6326 };
6327
6328 static const float nomodelcolor4f[6*4] =
6329 {
6330         0.0f, 0.0f, 0.5f, 1.0f,
6331         0.0f, 0.0f, 0.5f, 1.0f,
6332         0.0f, 0.5f, 0.0f, 1.0f,
6333         0.0f, 0.5f, 0.0f, 1.0f,
6334         0.5f, 0.0f, 0.0f, 1.0f,
6335         0.5f, 0.0f, 0.0f, 1.0f
6336 };
6337
6338 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6339 {
6340         int i;
6341         float f1, f2, *c;
6342         float color4f[6*4];
6343
6344         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);
6345
6346         // this is only called once per entity so numsurfaces is always 1, and
6347         // surfacelist is always {0}, so this code does not handle batches
6348
6349         if (rsurface.ent_flags & RENDER_ADDITIVE)
6350         {
6351                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6352                 GL_DepthMask(false);
6353         }
6354         else if (ent->alpha < 1)
6355         {
6356                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6357                 GL_DepthMask(false);
6358         }
6359         else
6360         {
6361                 GL_BlendFunc(GL_ONE, GL_ZERO);
6362                 GL_DepthMask(true);
6363         }
6364         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6365         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6366         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6367         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6368         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6369         for (i = 0, c = color4f;i < 6;i++, c += 4)
6370         {
6371                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6372                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6373                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6374                 c[3] *= ent->alpha;
6375         }
6376         if (r_refdef.fogenabled)
6377         {
6378                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6379                 {
6380                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6381                         f2 = 1 - f1;
6382                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6383                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6384                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6385                 }
6386         }
6387 //      R_Mesh_ResetTextureState();
6388         R_SetupShader_Generic_NoTexture(false, false);
6389         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6390         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6391 }
6392
6393 void R_DrawNoModel(entity_render_t *ent)
6394 {
6395         vec3_t org;
6396         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6397         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6398                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6399         else
6400                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6401 }
6402
6403 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6404 {
6405         vec3_t right1, right2, diff, normal;
6406
6407         VectorSubtract (org2, org1, normal);
6408
6409         // calculate 'right' vector for start
6410         VectorSubtract (r_refdef.view.origin, org1, diff);
6411         CrossProduct (normal, diff, right1);
6412         VectorNormalize (right1);
6413
6414         // calculate 'right' vector for end
6415         VectorSubtract (r_refdef.view.origin, org2, diff);
6416         CrossProduct (normal, diff, right2);
6417         VectorNormalize (right2);
6418
6419         vert[ 0] = org1[0] + width * right1[0];
6420         vert[ 1] = org1[1] + width * right1[1];
6421         vert[ 2] = org1[2] + width * right1[2];
6422         vert[ 3] = org1[0] - width * right1[0];
6423         vert[ 4] = org1[1] - width * right1[1];
6424         vert[ 5] = org1[2] - width * right1[2];
6425         vert[ 6] = org2[0] - width * right2[0];
6426         vert[ 7] = org2[1] - width * right2[1];
6427         vert[ 8] = org2[2] - width * right2[2];
6428         vert[ 9] = org2[0] + width * right2[0];
6429         vert[10] = org2[1] + width * right2[1];
6430         vert[11] = org2[2] + width * right2[2];
6431 }
6432
6433 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)
6434 {
6435         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6436         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6437         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6438         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6439         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6440         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6441         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6442         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6443         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6444         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6445         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6446         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6447 }
6448
6449 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6450 {
6451         int i;
6452         float *vertex3f;
6453         float v[3];
6454         VectorSet(v, x, y, z);
6455         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6456                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6457                         break;
6458         if (i == mesh->numvertices)
6459         {
6460                 if (mesh->numvertices < mesh->maxvertices)
6461                 {
6462                         VectorCopy(v, vertex3f);
6463                         mesh->numvertices++;
6464                 }
6465                 return mesh->numvertices;
6466         }
6467         else
6468                 return i;
6469 }
6470
6471 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6472 {
6473         int i;
6474         int *e, element[3];
6475         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6476         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6477         e = mesh->element3i + mesh->numtriangles * 3;
6478         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6479         {
6480                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6481                 if (mesh->numtriangles < mesh->maxtriangles)
6482                 {
6483                         *e++ = element[0];
6484                         *e++ = element[1];
6485                         *e++ = element[2];
6486                         mesh->numtriangles++;
6487                 }
6488                 element[1] = element[2];
6489         }
6490 }
6491
6492 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6493 {
6494         int i;
6495         int *e, element[3];
6496         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6497         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6498         e = mesh->element3i + mesh->numtriangles * 3;
6499         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6500         {
6501                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6502                 if (mesh->numtriangles < mesh->maxtriangles)
6503                 {
6504                         *e++ = element[0];
6505                         *e++ = element[1];
6506                         *e++ = element[2];
6507                         mesh->numtriangles++;
6508                 }
6509                 element[1] = element[2];
6510         }
6511 }
6512
6513 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6514 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6515 {
6516         int planenum, planenum2;
6517         int w;
6518         int tempnumpoints;
6519         mplane_t *plane, *plane2;
6520         double maxdist;
6521         double temppoints[2][256*3];
6522         // figure out how large a bounding box we need to properly compute this brush
6523         maxdist = 0;
6524         for (w = 0;w < numplanes;w++)
6525                 maxdist = max(maxdist, fabs(planes[w].dist));
6526         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6527         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6528         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6529         {
6530                 w = 0;
6531                 tempnumpoints = 4;
6532                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6533                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6534                 {
6535                         if (planenum2 == planenum)
6536                                 continue;
6537                         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);
6538                         w = !w;
6539                 }
6540                 if (tempnumpoints < 3)
6541                         continue;
6542                 // generate elements forming a triangle fan for this polygon
6543                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6544         }
6545 }
6546
6547 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6548 {
6549         if(parms[0] == 0 && parms[1] == 0)
6550                 return false;
6551         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6552                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6553                         return false;
6554         return true;
6555 }
6556
6557 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6558 {
6559         double index, f;
6560         index = parms[2] + rsurface.shadertime * parms[3];
6561         index -= floor(index);
6562         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6563         {
6564         default:
6565         case Q3WAVEFUNC_NONE:
6566         case Q3WAVEFUNC_NOISE:
6567         case Q3WAVEFUNC_COUNT:
6568                 f = 0;
6569                 break;
6570         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6571         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6572         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6573         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6574         case Q3WAVEFUNC_TRIANGLE:
6575                 index *= 4;
6576                 f = index - floor(index);
6577                 if (index < 1)
6578                 {
6579                         // f = f;
6580                 }
6581                 else if (index < 2)
6582                         f = 1 - f;
6583                 else if (index < 3)
6584                         f = -f;
6585                 else
6586                         f = -(1 - f);
6587                 break;
6588         }
6589         f = parms[0] + parms[1] * f;
6590         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6591                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6592         return (float) f;
6593 }
6594
6595 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6596 {
6597         int w, h, idx;
6598         float shadertime;
6599         float f;
6600         float offsetd[2];
6601         float tcmat[12];
6602         matrix4x4_t matrix, temp;
6603         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6604         // it's better to have one huge fixup every 9 hours than gradual
6605         // degradation over time which looks consistently bad after many hours.
6606         //
6607         // tcmod scroll in particular suffers from this degradation which can't be
6608         // effectively worked around even with floor() tricks because we don't
6609         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6610         // a workaround involving floor() would be incorrect anyway...
6611         shadertime = rsurface.shadertime;
6612         if (shadertime >= 32768.0f)
6613                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6614         switch(tcmod->tcmod)
6615         {
6616                 case Q3TCMOD_COUNT:
6617                 case Q3TCMOD_NONE:
6618                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6619                                 matrix = r_waterscrollmatrix;
6620                         else
6621                                 matrix = identitymatrix;
6622                         break;
6623                 case Q3TCMOD_ENTITYTRANSLATE:
6624                         // this is used in Q3 to allow the gamecode to control texcoord
6625                         // scrolling on the entity, which is not supported in darkplaces yet.
6626                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6627                         break;
6628                 case Q3TCMOD_ROTATE:
6629                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6630                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6631                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6632                         break;
6633                 case Q3TCMOD_SCALE:
6634                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6635                         break;
6636                 case Q3TCMOD_SCROLL:
6637                         // this particular tcmod is a "bug for bug" compatible one with regards to
6638                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6639                         // specifically did the wrapping and so we must mimic that...
6640                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6641                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6642                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6643                         break;
6644                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6645                         w = (int) tcmod->parms[0];
6646                         h = (int) tcmod->parms[1];
6647                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6648                         f = f - floor(f);
6649                         idx = (int) floor(f * w * h);
6650                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6651                         break;
6652                 case Q3TCMOD_STRETCH:
6653                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6654                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6655                         break;
6656                 case Q3TCMOD_TRANSFORM:
6657                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6658                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6659                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6660                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6661                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6662                         break;
6663                 case Q3TCMOD_TURBULENT:
6664                         // this is handled in the RSurf_PrepareVertices function
6665                         matrix = identitymatrix;
6666                         break;
6667         }
6668         temp = *texmatrix;
6669         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6670 }
6671
6672 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6673 {
6674         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6675         char name[MAX_QPATH];
6676         skinframe_t *skinframe;
6677         unsigned char pixels[296*194];
6678         strlcpy(cache->name, skinname, sizeof(cache->name));
6679         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6680         if (developer_loading.integer)
6681                 Con_Printf("loading %s\n", name);
6682         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6683         if (!skinframe || !skinframe->base)
6684         {
6685                 unsigned char *f;
6686                 fs_offset_t filesize;
6687                 skinframe = NULL;
6688                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6689                 if (f)
6690                 {
6691                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6692                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6693                         Mem_Free(f);
6694                 }
6695         }
6696         cache->skinframe = skinframe;
6697 }
6698
6699 texture_t *R_GetCurrentTexture(texture_t *t)
6700 {
6701         int i, q;
6702         const entity_render_t *ent = rsurface.entity;
6703         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6704         q3shaderinfo_layer_tcmod_t *tcmod;
6705         float specularscale = 0.0f;
6706
6707         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6708                 return t->currentframe;
6709         t->update_lastrenderframe = r_textureframe;
6710         t->update_lastrenderentity = (void *)ent;
6711
6712         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6713                 t->camera_entity = ent->entitynumber;
6714         else
6715                 t->camera_entity = 0;
6716
6717         // switch to an alternate material if this is a q1bsp animated material
6718         {
6719                 texture_t *texture = t;
6720                 int s = rsurface.ent_skinnum;
6721                 if ((unsigned int)s >= (unsigned int)model->numskins)
6722                         s = 0;
6723                 if (model->skinscenes)
6724                 {
6725                         if (model->skinscenes[s].framecount > 1)
6726                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6727                         else
6728                                 s = model->skinscenes[s].firstframe;
6729                 }
6730                 if (s > 0)
6731                         t = t + s * model->num_surfaces;
6732                 if (t->animated)
6733                 {
6734                         // use an alternate animation if the entity's frame is not 0,
6735                         // and only if the texture has an alternate animation
6736                         if (t->animated == 2) // q2bsp
6737                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6738                         else if (rsurface.ent_alttextures && t->anim_total[1])
6739                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6740                         else
6741                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6742                 }
6743                 texture->currentframe = t;
6744         }
6745
6746         // update currentskinframe to be a qw skin or animation frame
6747         if (rsurface.ent_qwskin >= 0)
6748         {
6749                 i = rsurface.ent_qwskin;
6750                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6751                 {
6752                         r_qwskincache_size = cl.maxclients;
6753                         if (r_qwskincache)
6754                                 Mem_Free(r_qwskincache);
6755                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6756                 }
6757                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6758                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6759                 t->currentskinframe = r_qwskincache[i].skinframe;
6760                 if (t->materialshaderpass && t->currentskinframe == NULL)
6761                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6762         }
6763         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6764                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6765         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6766                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6767
6768         t->currentmaterialflags = t->basematerialflags;
6769         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6770         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6771                 t->currentalpha *= r_wateralpha.value;
6772         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6773                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6774         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6775                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6776
6777         // decide on which type of lighting to use for this surface
6778         if (rsurface.entity->render_modellight_forced)
6779                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6780         if (rsurface.entity->render_rtlight_disabled)
6781                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6782         if (rsurface.entity->render_lightgrid)
6783                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6784         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6785         {
6786                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6787                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6788                 for (q = 0; q < 3; q++)
6789                 {
6790                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6791                         t->render_modellight_lightdir[q] = q == 2;
6792                         t->render_modellight_ambient[q] = 1;
6793                         t->render_modellight_diffuse[q] = 0;
6794                         t->render_modellight_specular[q] = 0;
6795                         t->render_lightmap_ambient[q] = 0;
6796                         t->render_lightmap_diffuse[q] = 0;
6797                         t->render_lightmap_specular[q] = 0;
6798                         t->render_rtlight_diffuse[q] = 0;
6799                         t->render_rtlight_specular[q] = 0;
6800                 }
6801         }
6802         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6803         {
6804                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6805                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6806                 for (q = 0; q < 3; q++)
6807                 {
6808                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6809                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6810                         t->render_modellight_lightdir[q] = q == 2;
6811                         t->render_modellight_diffuse[q] = 0;
6812                         t->render_modellight_specular[q] = 0;
6813                         t->render_lightmap_ambient[q] = 0;
6814                         t->render_lightmap_diffuse[q] = 0;
6815                         t->render_lightmap_specular[q] = 0;
6816                         t->render_rtlight_diffuse[q] = 0;
6817                         t->render_rtlight_specular[q] = 0;
6818                 }
6819         }
6820         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6821         {
6822                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
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] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6831                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6832                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6833                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6834                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6835                 }
6836         }
6837         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6838         {
6839                 // ambient + single direction light (modellight)
6840                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6841                 for (q = 0; q < 3; q++)
6842                 {
6843                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6844                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6845                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6846                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6847                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6848                         t->render_lightmap_ambient[q] = 0;
6849                         t->render_lightmap_diffuse[q] = 0;
6850                         t->render_lightmap_specular[q] = 0;
6851                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6852                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6853                 }
6854         }
6855         else
6856         {
6857                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6858                 for (q = 0; q < 3; q++)
6859                 {
6860                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6861                         t->render_modellight_lightdir[q] = q == 2;
6862                         t->render_modellight_ambient[q] = 0;
6863                         t->render_modellight_diffuse[q] = 0;
6864                         t->render_modellight_specular[q] = 0;
6865                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6866                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6867                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6868                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6869                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6870                 }
6871         }
6872
6873         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6874         {
6875                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6876                 // attribute, we punt it to the lightmap path and hope for the best,
6877                 // but lighting doesn't work.
6878                 //
6879                 // FIXME: this is fine for effects but CSQC polygons should be subject
6880                 // to lighting.
6881                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6882                 for (q = 0; q < 3; q++)
6883                 {
6884                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6885                         t->render_modellight_lightdir[q] = q == 2;
6886                         t->render_modellight_ambient[q] = 0;
6887                         t->render_modellight_diffuse[q] = 0;
6888                         t->render_modellight_specular[q] = 0;
6889                         t->render_lightmap_ambient[q] = 0;
6890                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6891                         t->render_lightmap_specular[q] = 0;
6892                         t->render_rtlight_diffuse[q] = 0;
6893                         t->render_rtlight_specular[q] = 0;
6894                 }
6895         }
6896
6897         for (q = 0; q < 3; q++)
6898         {
6899                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6900                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6901         }
6902
6903         if (rsurface.ent_flags & RENDER_ADDITIVE)
6904                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6905         else if (t->currentalpha < 1)
6906                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6907         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6908         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6909                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6910         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6911                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6912         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6913                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6914         if (t->backgroundshaderpass)
6915                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6916         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6917         {
6918                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6919                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6920         }
6921         else
6922                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6923         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6924         {
6925                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6926                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6927         }
6928         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6929                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6930
6931         // there is no tcmod
6932         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6933         {
6934                 t->currenttexmatrix = r_waterscrollmatrix;
6935                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6936         }
6937         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6938         {
6939                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6940                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6941         }
6942
6943         if (t->materialshaderpass)
6944                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6945                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6946
6947         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6948         if (t->currentskinframe->qpixels)
6949                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6950         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6951         if (!t->basetexture)
6952                 t->basetexture = r_texture_notexture;
6953         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6954         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6955         t->nmaptexture = t->currentskinframe->nmap;
6956         if (!t->nmaptexture)
6957                 t->nmaptexture = r_texture_blanknormalmap;
6958         t->glosstexture = r_texture_black;
6959         t->glowtexture = t->currentskinframe->glow;
6960         t->fogtexture = t->currentskinframe->fog;
6961         t->reflectmasktexture = t->currentskinframe->reflect;
6962         if (t->backgroundshaderpass)
6963         {
6964                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6965                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6966                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6967                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6968                 t->backgroundglosstexture = r_texture_black;
6969                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6970                 if (!t->backgroundnmaptexture)
6971                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6972                 // make sure that if glow is going to be used, both textures are not NULL
6973                 if (!t->backgroundglowtexture && t->glowtexture)
6974                         t->backgroundglowtexture = r_texture_black;
6975                 if (!t->glowtexture && t->backgroundglowtexture)
6976                         t->glowtexture = r_texture_black;
6977         }
6978         else
6979         {
6980                 t->backgroundbasetexture = r_texture_white;
6981                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6982                 t->backgroundglosstexture = r_texture_black;
6983                 t->backgroundglowtexture = NULL;
6984         }
6985         t->specularpower = r_shadow_glossexponent.value;
6986         // TODO: store reference values for these in the texture?
6987         if (r_shadow_gloss.integer > 0)
6988         {
6989                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6990                 {
6991                         if (r_shadow_glossintensity.value > 0)
6992                         {
6993                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6994                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6995                                 specularscale = r_shadow_glossintensity.value;
6996                         }
6997                 }
6998                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6999                 {
7000                         t->glosstexture = r_texture_white;
7001                         t->backgroundglosstexture = r_texture_white;
7002                         specularscale = r_shadow_gloss2intensity.value;
7003                         t->specularpower = r_shadow_gloss2exponent.value;
7004                 }
7005         }
7006         specularscale *= t->specularscalemod;
7007         t->specularpower *= t->specularpowermod;
7008
7009         // lightmaps mode looks bad with dlights using actual texturing, so turn
7010         // off the colormap and glossmap, but leave the normalmap on as it still
7011         // accurately represents the shading involved
7012         if (gl_lightmaps.integer)
7013         {
7014                 t->basetexture = r_texture_grey128;
7015                 t->pantstexture = r_texture_black;
7016                 t->shirttexture = r_texture_black;
7017                 if (gl_lightmaps.integer < 2)
7018                         t->nmaptexture = r_texture_blanknormalmap;
7019                 t->glosstexture = r_texture_black;
7020                 t->glowtexture = NULL;
7021                 t->fogtexture = NULL;
7022                 t->reflectmasktexture = NULL;
7023                 t->backgroundbasetexture = NULL;
7024                 if (gl_lightmaps.integer < 2)
7025                         t->backgroundnmaptexture = r_texture_blanknormalmap;
7026                 t->backgroundglosstexture = r_texture_black;
7027                 t->backgroundglowtexture = NULL;
7028                 specularscale = 0;
7029                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7030         }
7031
7032         if (specularscale != 1.0f)
7033         {
7034                 for (q = 0; q < 3; q++)
7035                 {
7036                         t->render_modellight_specular[q] *= specularscale;
7037                         t->render_lightmap_specular[q] *= specularscale;
7038                         t->render_rtlight_specular[q] *= specularscale;
7039                 }
7040         }
7041
7042         t->currentblendfunc[0] = GL_ONE;
7043         t->currentblendfunc[1] = GL_ZERO;
7044         if (t->currentmaterialflags & MATERIALFLAG_ADD)
7045         {
7046                 t->currentblendfunc[0] = GL_SRC_ALPHA;
7047                 t->currentblendfunc[1] = GL_ONE;
7048         }
7049         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7050         {
7051                 t->currentblendfunc[0] = GL_SRC_ALPHA;
7052                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
7053         }
7054         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7055         {
7056                 t->currentblendfunc[0] = t->customblendfunc[0];
7057                 t->currentblendfunc[1] = t->customblendfunc[1];
7058         }
7059
7060         return t;
7061 }
7062
7063 rsurfacestate_t rsurface;
7064
7065 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7066 {
7067         dp_model_t *model = ent->model;
7068         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7069         //      return;
7070         rsurface.entity = (entity_render_t *)ent;
7071         rsurface.skeleton = ent->skeleton;
7072         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7073         rsurface.ent_skinnum = ent->skinnum;
7074         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;
7075         rsurface.ent_flags = ent->flags;
7076         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7077                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7078         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7079         rsurface.matrix = ent->matrix;
7080         rsurface.inversematrix = ent->inversematrix;
7081         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7082         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7083         R_EntityMatrix(&rsurface.matrix);
7084         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7085         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7086         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7087         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7088         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7089         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7090         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7091         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7092         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7093         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7094         if (ent->model->brush.submodel && !prepass)
7095         {
7096                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7097                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7098         }
7099         // if the animcache code decided it should use the shader path, skip the deform step
7100         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7101         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7102         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7103         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7104         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7105         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7106         {
7107                 if (ent->animcache_vertex3f)
7108                 {
7109                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7110                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7111                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7112                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7113                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7114                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7115                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7116                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7117                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7118                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7119                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7120                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7121                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7122                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7123                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7124                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7125                 }
7126                 else if (wanttangents)
7127                 {
7128                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7129                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7130                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7131                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7132                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7133                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7134                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7135                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7136                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7137                         rsurface.modelvertex3f_vertexbuffer = NULL;
7138                         rsurface.modelvertex3f_bufferoffset = 0;
7139                         rsurface.modelvertex3f_vertexbuffer = 0;
7140                         rsurface.modelvertex3f_bufferoffset = 0;
7141                         rsurface.modelsvector3f_vertexbuffer = 0;
7142                         rsurface.modelsvector3f_bufferoffset = 0;
7143                         rsurface.modeltvector3f_vertexbuffer = 0;
7144                         rsurface.modeltvector3f_bufferoffset = 0;
7145                         rsurface.modelnormal3f_vertexbuffer = 0;
7146                         rsurface.modelnormal3f_bufferoffset = 0;
7147                 }
7148                 else if (wantnormals)
7149                 {
7150                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7151                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7152                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7153                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7154                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7155                         rsurface.modelsvector3f = NULL;
7156                         rsurface.modeltvector3f = NULL;
7157                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7158                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7159                         rsurface.modelvertex3f_vertexbuffer = NULL;
7160                         rsurface.modelvertex3f_bufferoffset = 0;
7161                         rsurface.modelvertex3f_vertexbuffer = 0;
7162                         rsurface.modelvertex3f_bufferoffset = 0;
7163                         rsurface.modelsvector3f_vertexbuffer = 0;
7164                         rsurface.modelsvector3f_bufferoffset = 0;
7165                         rsurface.modeltvector3f_vertexbuffer = 0;
7166                         rsurface.modeltvector3f_bufferoffset = 0;
7167                         rsurface.modelnormal3f_vertexbuffer = 0;
7168                         rsurface.modelnormal3f_bufferoffset = 0;
7169                 }
7170                 else
7171                 {
7172                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7173                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7174                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7175                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7176                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7177                         rsurface.modelsvector3f = NULL;
7178                         rsurface.modeltvector3f = NULL;
7179                         rsurface.modelnormal3f = NULL;
7180                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7181                         rsurface.modelvertex3f_vertexbuffer = NULL;
7182                         rsurface.modelvertex3f_bufferoffset = 0;
7183                         rsurface.modelvertex3f_vertexbuffer = 0;
7184                         rsurface.modelvertex3f_bufferoffset = 0;
7185                         rsurface.modelsvector3f_vertexbuffer = 0;
7186                         rsurface.modelsvector3f_bufferoffset = 0;
7187                         rsurface.modeltvector3f_vertexbuffer = 0;
7188                         rsurface.modeltvector3f_bufferoffset = 0;
7189                         rsurface.modelnormal3f_vertexbuffer = 0;
7190                         rsurface.modelnormal3f_bufferoffset = 0;
7191                 }
7192                 rsurface.modelgeneratedvertex = true;
7193         }
7194         else
7195         {
7196                 if (rsurface.entityskeletaltransform3x4)
7197                 {
7198                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7199                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7200                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7201                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7202                 }
7203                 else
7204                 {
7205                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7206                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7207                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7208                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7209                 }
7210                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7211                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7212                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7213                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7214                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7215                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7216                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7217                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7218                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7219                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7220                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7221                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7222                 rsurface.modelgeneratedvertex = false;
7223         }
7224         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7225         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7226         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7227         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7228         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7229         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7230         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7231         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7232         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7233         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7234         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7235         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7236         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7237         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7238         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7239         rsurface.modelelement3i = model->surfmesh.data_element3i;
7240         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7241         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7242         rsurface.modelelement3s = model->surfmesh.data_element3s;
7243         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7244         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7245         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7246         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7247         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7248         rsurface.modelsurfaces = model->data_surfaces;
7249         rsurface.batchgeneratedvertex = false;
7250         rsurface.batchfirstvertex = 0;
7251         rsurface.batchnumvertices = 0;
7252         rsurface.batchfirsttriangle = 0;
7253         rsurface.batchnumtriangles = 0;
7254         rsurface.batchvertex3f  = NULL;
7255         rsurface.batchvertex3f_vertexbuffer = NULL;
7256         rsurface.batchvertex3f_bufferoffset = 0;
7257         rsurface.batchsvector3f = NULL;
7258         rsurface.batchsvector3f_vertexbuffer = NULL;
7259         rsurface.batchsvector3f_bufferoffset = 0;
7260         rsurface.batchtvector3f = NULL;
7261         rsurface.batchtvector3f_vertexbuffer = NULL;
7262         rsurface.batchtvector3f_bufferoffset = 0;
7263         rsurface.batchnormal3f  = NULL;
7264         rsurface.batchnormal3f_vertexbuffer = NULL;
7265         rsurface.batchnormal3f_bufferoffset = 0;
7266         rsurface.batchlightmapcolor4f = NULL;
7267         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7268         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7269         rsurface.batchtexcoordtexture2f = NULL;
7270         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7271         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7272         rsurface.batchtexcoordlightmap2f = NULL;
7273         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7274         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7275         rsurface.batchskeletalindex4ub = NULL;
7276         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7277         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7278         rsurface.batchskeletalweight4ub = NULL;
7279         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7280         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7281         rsurface.batchelement3i = NULL;
7282         rsurface.batchelement3i_indexbuffer = NULL;
7283         rsurface.batchelement3i_bufferoffset = 0;
7284         rsurface.batchelement3s = NULL;
7285         rsurface.batchelement3s_indexbuffer = NULL;
7286         rsurface.batchelement3s_bufferoffset = 0;
7287         rsurface.forcecurrenttextureupdate = false;
7288 }
7289
7290 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)
7291 {
7292         rsurface.entity = r_refdef.scene.worldentity;
7293         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7294                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7295                 // A better approach could be making this copy only once per frame.
7296                 static entity_render_t custom_entity;
7297                 int q;
7298                 custom_entity = *rsurface.entity;
7299                 for (q = 0; q < 3; ++q) {
7300                         float colormod = q == 0 ? r : q == 1 ? g : b;
7301                         custom_entity.render_fullbright[q] *= colormod;
7302                         custom_entity.render_modellight_ambient[q] *= colormod;
7303                         custom_entity.render_modellight_diffuse[q] *= colormod;
7304                         custom_entity.render_lightmap_ambient[q] *= colormod;
7305                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7306                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7307                 }
7308                 custom_entity.alpha *= a;
7309                 rsurface.entity = &custom_entity;
7310         }
7311         rsurface.skeleton = NULL;
7312         rsurface.ent_skinnum = 0;
7313         rsurface.ent_qwskin = -1;
7314         rsurface.ent_flags = entflags;
7315         rsurface.shadertime = r_refdef.scene.time - shadertime;
7316         rsurface.modelnumvertices = numvertices;
7317         rsurface.modelnumtriangles = numtriangles;
7318         rsurface.matrix = *matrix;
7319         rsurface.inversematrix = *inversematrix;
7320         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7321         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7322         R_EntityMatrix(&rsurface.matrix);
7323         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7324         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7325         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7326         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7327         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7328         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7329         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7330         rsurface.frameblend[0].lerp = 1;
7331         rsurface.ent_alttextures = false;
7332         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7333         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7334         rsurface.entityskeletaltransform3x4 = NULL;
7335         rsurface.entityskeletaltransform3x4buffer = NULL;
7336         rsurface.entityskeletaltransform3x4offset = 0;
7337         rsurface.entityskeletaltransform3x4size = 0;
7338         rsurface.entityskeletalnumtransforms = 0;
7339         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7340         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7341         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7342         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7343         if (wanttangents)
7344         {
7345                 rsurface.modelvertex3f = (float *)vertex3f;
7346                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7347                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7348                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7349         }
7350         else if (wantnormals)
7351         {
7352                 rsurface.modelvertex3f = (float *)vertex3f;
7353                 rsurface.modelsvector3f = NULL;
7354                 rsurface.modeltvector3f = NULL;
7355                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7356         }
7357         else
7358         {
7359                 rsurface.modelvertex3f = (float *)vertex3f;
7360                 rsurface.modelsvector3f = NULL;
7361                 rsurface.modeltvector3f = NULL;
7362                 rsurface.modelnormal3f = NULL;
7363         }
7364         rsurface.modelvertex3f_vertexbuffer = 0;
7365         rsurface.modelvertex3f_bufferoffset = 0;
7366         rsurface.modelsvector3f_vertexbuffer = 0;
7367         rsurface.modelsvector3f_bufferoffset = 0;
7368         rsurface.modeltvector3f_vertexbuffer = 0;
7369         rsurface.modeltvector3f_bufferoffset = 0;
7370         rsurface.modelnormal3f_vertexbuffer = 0;
7371         rsurface.modelnormal3f_bufferoffset = 0;
7372         rsurface.modelgeneratedvertex = true;
7373         rsurface.modellightmapcolor4f  = (float *)color4f;
7374         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7375         rsurface.modellightmapcolor4f_bufferoffset = 0;
7376         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7377         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7378         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7379         rsurface.modeltexcoordlightmap2f  = NULL;
7380         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7381         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7382         rsurface.modelskeletalindex4ub = NULL;
7383         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7384         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7385         rsurface.modelskeletalweight4ub = NULL;
7386         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7387         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7388         rsurface.modelelement3i = (int *)element3i;
7389         rsurface.modelelement3i_indexbuffer = NULL;
7390         rsurface.modelelement3i_bufferoffset = 0;
7391         rsurface.modelelement3s = (unsigned short *)element3s;
7392         rsurface.modelelement3s_indexbuffer = NULL;
7393         rsurface.modelelement3s_bufferoffset = 0;
7394         rsurface.modellightmapoffsets = NULL;
7395         rsurface.modelsurfaces = NULL;
7396         rsurface.batchgeneratedvertex = false;
7397         rsurface.batchfirstvertex = 0;
7398         rsurface.batchnumvertices = 0;
7399         rsurface.batchfirsttriangle = 0;
7400         rsurface.batchnumtriangles = 0;
7401         rsurface.batchvertex3f  = NULL;
7402         rsurface.batchvertex3f_vertexbuffer = NULL;
7403         rsurface.batchvertex3f_bufferoffset = 0;
7404         rsurface.batchsvector3f = NULL;
7405         rsurface.batchsvector3f_vertexbuffer = NULL;
7406         rsurface.batchsvector3f_bufferoffset = 0;
7407         rsurface.batchtvector3f = NULL;
7408         rsurface.batchtvector3f_vertexbuffer = NULL;
7409         rsurface.batchtvector3f_bufferoffset = 0;
7410         rsurface.batchnormal3f  = NULL;
7411         rsurface.batchnormal3f_vertexbuffer = NULL;
7412         rsurface.batchnormal3f_bufferoffset = 0;
7413         rsurface.batchlightmapcolor4f = NULL;
7414         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7415         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7416         rsurface.batchtexcoordtexture2f = NULL;
7417         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7418         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7419         rsurface.batchtexcoordlightmap2f = NULL;
7420         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7421         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7422         rsurface.batchskeletalindex4ub = NULL;
7423         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7424         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7425         rsurface.batchskeletalweight4ub = NULL;
7426         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7427         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7428         rsurface.batchelement3i = NULL;
7429         rsurface.batchelement3i_indexbuffer = NULL;
7430         rsurface.batchelement3i_bufferoffset = 0;
7431         rsurface.batchelement3s = NULL;
7432         rsurface.batchelement3s_indexbuffer = NULL;
7433         rsurface.batchelement3s_bufferoffset = 0;
7434         rsurface.forcecurrenttextureupdate = true;
7435
7436         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7437         {
7438                 if ((wantnormals || wanttangents) && !normal3f)
7439                 {
7440                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7441                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7442                 }
7443                 if (wanttangents && !svector3f)
7444                 {
7445                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7446                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7447                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7448                 }
7449         }
7450 }
7451
7452 float RSurf_FogPoint(const float *v)
7453 {
7454         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7455         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7456         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7457         float FogHeightFade = r_refdef.fogheightfade;
7458         float fogfrac;
7459         unsigned int fogmasktableindex;
7460         if (r_refdef.fogplaneviewabove)
7461                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7462         else
7463                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7464         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7465         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7466 }
7467
7468 float RSurf_FogVertex(const float *v)
7469 {
7470         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7471         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7472         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7473         float FogHeightFade = rsurface.fogheightfade;
7474         float fogfrac;
7475         unsigned int fogmasktableindex;
7476         if (r_refdef.fogplaneviewabove)
7477                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7478         else
7479                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7480         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7481         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7482 }
7483
7484 void RSurf_UploadBuffersForBatch(void)
7485 {
7486         // 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)
7487         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7488         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7489                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7490         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7491                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7492         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7493                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7494         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7495                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7496         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7497                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7498         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7499                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7500         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7501                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7502         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7503                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7504         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7505                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7506
7507         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7508                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7509         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7510                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7511
7512         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7513         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7514         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7515         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7516         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7517         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7518         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7519         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7520         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7521         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7522 }
7523
7524 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7525 {
7526         int i;
7527         for (i = 0;i < numelements;i++)
7528                 outelement3i[i] = inelement3i[i] + adjust;
7529 }
7530
7531 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7532 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7533 {
7534         int deformindex;
7535         int firsttriangle;
7536         int numtriangles;
7537         int firstvertex;
7538         int endvertex;
7539         int numvertices;
7540         int surfacefirsttriangle;
7541         int surfacenumtriangles;
7542         int surfacefirstvertex;
7543         int surfaceendvertex;
7544         int surfacenumvertices;
7545         int batchnumsurfaces = texturenumsurfaces;
7546         int batchnumvertices;
7547         int batchnumtriangles;
7548         int i, j;
7549         qboolean gaps;
7550         qboolean dynamicvertex;
7551         float amplitude;
7552         float animpos;
7553         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7554         float waveparms[4];
7555         unsigned char *ub;
7556         q3shaderinfo_deform_t *deform;
7557         const msurface_t *surface, *firstsurface;
7558         if (!texturenumsurfaces)
7559                 return;
7560         // find vertex range of this surface batch
7561         gaps = false;
7562         firstsurface = texturesurfacelist[0];
7563         firsttriangle = firstsurface->num_firsttriangle;
7564         batchnumvertices = 0;
7565         batchnumtriangles = 0;
7566         firstvertex = endvertex = firstsurface->num_firstvertex;
7567         for (i = 0;i < texturenumsurfaces;i++)
7568         {
7569                 surface = texturesurfacelist[i];
7570                 if (surface != firstsurface + i)
7571                         gaps = true;
7572                 surfacefirstvertex = surface->num_firstvertex;
7573                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7574                 surfacenumvertices = surface->num_vertices;
7575                 surfacenumtriangles = surface->num_triangles;
7576                 if (firstvertex > surfacefirstvertex)
7577                         firstvertex = surfacefirstvertex;
7578                 if (endvertex < surfaceendvertex)
7579                         endvertex = surfaceendvertex;
7580                 batchnumvertices += surfacenumvertices;
7581                 batchnumtriangles += surfacenumtriangles;
7582         }
7583
7584         r_refdef.stats[r_stat_batch_batches]++;
7585         if (gaps)
7586                 r_refdef.stats[r_stat_batch_withgaps]++;
7587         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7588         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7589         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7590
7591         // we now know the vertex range used, and if there are any gaps in it
7592         rsurface.batchfirstvertex = firstvertex;
7593         rsurface.batchnumvertices = endvertex - firstvertex;
7594         rsurface.batchfirsttriangle = firsttriangle;
7595         rsurface.batchnumtriangles = batchnumtriangles;
7596
7597         // check if any dynamic vertex processing must occur
7598         dynamicvertex = false;
7599
7600         // we must use vertexbuffers for rendering, we can upload vertex buffers
7601         // easily enough but if the basevertex is non-zero it becomes more
7602         // difficult, so force dynamicvertex path in that case - it's suboptimal
7603         // but the most optimal case is to have the geometry sources provide their
7604         // own anyway.
7605         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7606                 dynamicvertex = true;
7607
7608         // a cvar to force the dynamic vertex path to be taken, for debugging
7609         if (r_batch_debugdynamicvertexpath.integer)
7610         {
7611                 if (!dynamicvertex)
7612                 {
7613                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7614                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7615                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7616                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7617                 }
7618                 dynamicvertex = true;
7619         }
7620
7621         // if there is a chance of animated vertex colors, it's a dynamic batch
7622         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7623         {
7624                 if (!dynamicvertex)
7625                 {
7626                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7627                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7628                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7629                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7630                 }
7631                 dynamicvertex = true;
7632         }
7633
7634         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7635         {
7636                 switch (deform->deform)
7637                 {
7638                 default:
7639                 case Q3DEFORM_PROJECTIONSHADOW:
7640                 case Q3DEFORM_TEXT0:
7641                 case Q3DEFORM_TEXT1:
7642                 case Q3DEFORM_TEXT2:
7643                 case Q3DEFORM_TEXT3:
7644                 case Q3DEFORM_TEXT4:
7645                 case Q3DEFORM_TEXT5:
7646                 case Q3DEFORM_TEXT6:
7647                 case Q3DEFORM_TEXT7:
7648                 case Q3DEFORM_NONE:
7649                         break;
7650                 case Q3DEFORM_AUTOSPRITE:
7651                         if (!dynamicvertex)
7652                         {
7653                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7654                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7655                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7656                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7657                         }
7658                         dynamicvertex = true;
7659                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7660                         break;
7661                 case Q3DEFORM_AUTOSPRITE2:
7662                         if (!dynamicvertex)
7663                         {
7664                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7665                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7666                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7667                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7668                         }
7669                         dynamicvertex = true;
7670                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7671                         break;
7672                 case Q3DEFORM_NORMAL:
7673                         if (!dynamicvertex)
7674                         {
7675                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7676                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7677                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7678                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7679                         }
7680                         dynamicvertex = true;
7681                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7682                         break;
7683                 case Q3DEFORM_WAVE:
7684                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7685                                 break; // if wavefunc is a nop, ignore this transform
7686                         if (!dynamicvertex)
7687                         {
7688                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7689                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7690                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7691                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7692                         }
7693                         dynamicvertex = true;
7694                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7695                         break;
7696                 case Q3DEFORM_BULGE:
7697                         if (!dynamicvertex)
7698                         {
7699                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7700                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7701                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7702                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7703                         }
7704                         dynamicvertex = true;
7705                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7706                         break;
7707                 case Q3DEFORM_MOVE:
7708                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7709                                 break; // if wavefunc is a nop, ignore this transform
7710                         if (!dynamicvertex)
7711                         {
7712                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7713                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7714                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7715                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7716                         }
7717                         dynamicvertex = true;
7718                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7719                         break;
7720                 }
7721         }
7722         if (rsurface.texture->materialshaderpass)
7723         {
7724                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7725                 {
7726                 default:
7727                 case Q3TCGEN_TEXTURE:
7728                         break;
7729                 case Q3TCGEN_LIGHTMAP:
7730                         if (!dynamicvertex)
7731                         {
7732                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7733                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7734                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7735                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7736                         }
7737                         dynamicvertex = true;
7738                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7739                         break;
7740                 case Q3TCGEN_VECTOR:
7741                         if (!dynamicvertex)
7742                         {
7743                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7744                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7745                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7746                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7747                         }
7748                         dynamicvertex = true;
7749                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7750                         break;
7751                 case Q3TCGEN_ENVIRONMENT:
7752                         if (!dynamicvertex)
7753                         {
7754                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7755                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7756                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7757                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7758                         }
7759                         dynamicvertex = true;
7760                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7761                         break;
7762                 }
7763                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7764                 {
7765                         if (!dynamicvertex)
7766                         {
7767                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7768                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7769                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7770                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7771                         }
7772                         dynamicvertex = true;
7773                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7774                 }
7775         }
7776
7777         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7778         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7779         // we ensure this by treating the vertex batch as dynamic...
7780         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7781         {
7782                 if (!dynamicvertex)
7783                 {
7784                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7785                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7786                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7787                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7788                 }
7789                 dynamicvertex = true;
7790         }
7791
7792         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7793         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7794                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7795
7796         rsurface.batchvertex3f = rsurface.modelvertex3f;
7797         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7798         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7799         rsurface.batchsvector3f = rsurface.modelsvector3f;
7800         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7801         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7802         rsurface.batchtvector3f = rsurface.modeltvector3f;
7803         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7804         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7805         rsurface.batchnormal3f = rsurface.modelnormal3f;
7806         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7807         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7808         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7809         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7810         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7811         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7812         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7813         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7814         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7815         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7816         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7817         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7818         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7819         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7820         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7821         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7822         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7823         rsurface.batchelement3i = rsurface.modelelement3i;
7824         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7825         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7826         rsurface.batchelement3s = rsurface.modelelement3s;
7827         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7828         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7829         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7830         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7831         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7832         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7833         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7834
7835         // if any dynamic vertex processing has to occur in software, we copy the
7836         // entire surface list together before processing to rebase the vertices
7837         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7838         //
7839         // if any gaps exist and we do not have a static vertex buffer, we have to
7840         // copy the surface list together to avoid wasting upload bandwidth on the
7841         // vertices in the gaps.
7842         //
7843         // if gaps exist and we have a static vertex buffer, we can choose whether
7844         // to combine the index buffer ranges into one dynamic index buffer or
7845         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7846         //
7847         // in many cases the batch is reduced to one draw call.
7848
7849         rsurface.batchmultidraw = false;
7850         rsurface.batchmultidrawnumsurfaces = 0;
7851         rsurface.batchmultidrawsurfacelist = NULL;
7852
7853         if (!dynamicvertex)
7854         {
7855                 // static vertex data, just set pointers...
7856                 rsurface.batchgeneratedvertex = false;
7857                 // if there are gaps, we want to build a combined index buffer,
7858                 // otherwise use the original static buffer with an appropriate offset
7859                 if (gaps)
7860                 {
7861                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7862                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7863                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7864                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7865                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7866                         {
7867                                 rsurface.batchmultidraw = true;
7868                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7869                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7870                                 return;
7871                         }
7872                         // build a new triangle elements array for this batch
7873                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7874                         rsurface.batchfirsttriangle = 0;
7875                         numtriangles = 0;
7876                         for (i = 0;i < texturenumsurfaces;i++)
7877                         {
7878                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7879                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7880                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7881                                 numtriangles += surfacenumtriangles;
7882                         }
7883                         rsurface.batchelement3i_indexbuffer = NULL;
7884                         rsurface.batchelement3i_bufferoffset = 0;
7885                         rsurface.batchelement3s = NULL;
7886                         rsurface.batchelement3s_indexbuffer = NULL;
7887                         rsurface.batchelement3s_bufferoffset = 0;
7888                         if (endvertex <= 65536)
7889                         {
7890                                 // make a 16bit (unsigned short) index array if possible
7891                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7892                                 for (i = 0;i < numtriangles*3;i++)
7893                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7894                         }
7895                 }
7896                 else
7897                 {
7898                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7899                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7900                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7901                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7902                 }
7903                 return;
7904         }
7905
7906         // something needs software processing, do it for real...
7907         // we only directly handle separate array data in this case and then
7908         // generate interleaved data if needed...
7909         rsurface.batchgeneratedvertex = true;
7910         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7911         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7912         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7913         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7914
7915         // now copy the vertex data into a combined array and make an index array
7916         // (this is what Quake3 does all the time)
7917         // we also apply any skeletal animation here that would have been done in
7918         // the vertex shader, because most of the dynamic vertex animation cases
7919         // need actual vertex positions and normals
7920         //if (dynamicvertex)
7921         {
7922                 rsurface.batchvertex3f = NULL;
7923                 rsurface.batchvertex3f_vertexbuffer = NULL;
7924                 rsurface.batchvertex3f_bufferoffset = 0;
7925                 rsurface.batchsvector3f = NULL;
7926                 rsurface.batchsvector3f_vertexbuffer = NULL;
7927                 rsurface.batchsvector3f_bufferoffset = 0;
7928                 rsurface.batchtvector3f = NULL;
7929                 rsurface.batchtvector3f_vertexbuffer = NULL;
7930                 rsurface.batchtvector3f_bufferoffset = 0;
7931                 rsurface.batchnormal3f = NULL;
7932                 rsurface.batchnormal3f_vertexbuffer = NULL;
7933                 rsurface.batchnormal3f_bufferoffset = 0;
7934                 rsurface.batchlightmapcolor4f = NULL;
7935                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7936                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7937                 rsurface.batchtexcoordtexture2f = NULL;
7938                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7939                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7940                 rsurface.batchtexcoordlightmap2f = NULL;
7941                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7942                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7943                 rsurface.batchskeletalindex4ub = NULL;
7944                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7945                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7946                 rsurface.batchskeletalweight4ub = NULL;
7947                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7948                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7949                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7950                 rsurface.batchelement3i_indexbuffer = NULL;
7951                 rsurface.batchelement3i_bufferoffset = 0;
7952                 rsurface.batchelement3s = NULL;
7953                 rsurface.batchelement3s_indexbuffer = NULL;
7954                 rsurface.batchelement3s_bufferoffset = 0;
7955                 rsurface.batchskeletaltransform3x4buffer = NULL;
7956                 rsurface.batchskeletaltransform3x4offset = 0;
7957                 rsurface.batchskeletaltransform3x4size = 0;
7958                 // we'll only be setting up certain arrays as needed
7959                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7960                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7961                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7962                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7963                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7964                 {
7965                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7966                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7967                 }
7968                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7969                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7970                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7971                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7972                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7973                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7974                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7975                 {
7976                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7977                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7978                 }
7979                 numvertices = 0;
7980                 numtriangles = 0;
7981                 for (i = 0;i < texturenumsurfaces;i++)
7982                 {
7983                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7984                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7985                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7986                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7987                         // copy only the data requested
7988                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7989                         {
7990                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7991                                 {
7992                                         if (rsurface.batchvertex3f)
7993                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7994                                         else
7995                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7996                                 }
7997                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7998                                 {
7999                                         if (rsurface.modelnormal3f)
8000                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8001                                         else
8002                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8003                                 }
8004                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8005                                 {
8006                                         if (rsurface.modelsvector3f)
8007                                         {
8008                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8009                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8010                                         }
8011                                         else
8012                                         {
8013                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8014                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8015                                         }
8016                                 }
8017                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8018                                 {
8019                                         if (rsurface.modellightmapcolor4f)
8020                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8021                                         else
8022                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8023                                 }
8024                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8025                                 {
8026                                         if (rsurface.modeltexcoordtexture2f)
8027                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8028                                         else
8029                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8030                                 }
8031                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8032                                 {
8033                                         if (rsurface.modeltexcoordlightmap2f)
8034                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8035                                         else
8036                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8037                                 }
8038                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8039                                 {
8040                                         if (rsurface.modelskeletalindex4ub)
8041                                         {
8042                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8043                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8044                                         }
8045                                         else
8046                                         {
8047                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8048                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8049                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8050                                                 for (j = 0;j < surfacenumvertices;j++)
8051                                                         ub[j*4] = 255;
8052                                         }
8053                                 }
8054                         }
8055                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8056                         numvertices += surfacenumvertices;
8057                         numtriangles += surfacenumtriangles;
8058                 }
8059
8060                 // generate a 16bit index array as well if possible
8061                 // (in general, dynamic batches fit)
8062                 if (numvertices <= 65536)
8063                 {
8064                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8065                         for (i = 0;i < numtriangles*3;i++)
8066                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8067                 }
8068
8069                 // since we've copied everything, the batch now starts at 0
8070                 rsurface.batchfirstvertex = 0;
8071                 rsurface.batchnumvertices = batchnumvertices;
8072                 rsurface.batchfirsttriangle = 0;
8073                 rsurface.batchnumtriangles = batchnumtriangles;
8074         }
8075
8076         // apply skeletal animation that would have been done in the vertex shader
8077         if (rsurface.batchskeletaltransform3x4)
8078         {
8079                 const unsigned char *si;
8080                 const unsigned char *sw;
8081                 const float *t[4];
8082                 const float *b = rsurface.batchskeletaltransform3x4;
8083                 float *vp, *vs, *vt, *vn;
8084                 float w[4];
8085                 float m[3][4], n[3][4];
8086                 float tp[3], ts[3], tt[3], tn[3];
8087                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8088                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8089                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8090                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8091                 si = rsurface.batchskeletalindex4ub;
8092                 sw = rsurface.batchskeletalweight4ub;
8093                 vp = rsurface.batchvertex3f;
8094                 vs = rsurface.batchsvector3f;
8095                 vt = rsurface.batchtvector3f;
8096                 vn = rsurface.batchnormal3f;
8097                 memset(m[0], 0, sizeof(m));
8098                 memset(n[0], 0, sizeof(n));
8099                 for (i = 0;i < batchnumvertices;i++)
8100                 {
8101                         t[0] = b + si[0]*12;
8102                         if (sw[0] == 255)
8103                         {
8104                                 // common case - only one matrix
8105                                 m[0][0] = t[0][ 0];
8106                                 m[0][1] = t[0][ 1];
8107                                 m[0][2] = t[0][ 2];
8108                                 m[0][3] = t[0][ 3];
8109                                 m[1][0] = t[0][ 4];
8110                                 m[1][1] = t[0][ 5];
8111                                 m[1][2] = t[0][ 6];
8112                                 m[1][3] = t[0][ 7];
8113                                 m[2][0] = t[0][ 8];
8114                                 m[2][1] = t[0][ 9];
8115                                 m[2][2] = t[0][10];
8116                                 m[2][3] = t[0][11];
8117                         }
8118                         else if (sw[2] + sw[3])
8119                         {
8120                                 // blend 4 matrices
8121                                 t[1] = b + si[1]*12;
8122                                 t[2] = b + si[2]*12;
8123                                 t[3] = b + si[3]*12;
8124                                 w[0] = sw[0] * (1.0f / 255.0f);
8125                                 w[1] = sw[1] * (1.0f / 255.0f);
8126                                 w[2] = sw[2] * (1.0f / 255.0f);
8127                                 w[3] = sw[3] * (1.0f / 255.0f);
8128                                 // blend the matrices
8129                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8130                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8131                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8132                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8133                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8134                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8135                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8136                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8137                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8138                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8139                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8140                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8141                         }
8142                         else
8143                         {
8144                                 // blend 2 matrices
8145                                 t[1] = b + si[1]*12;
8146                                 w[0] = sw[0] * (1.0f / 255.0f);
8147                                 w[1] = sw[1] * (1.0f / 255.0f);
8148                                 // blend the matrices
8149                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8150                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8151                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8152                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8153                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8154                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8155                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8156                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8157                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8158                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8159                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8160                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8161                         }
8162                         si += 4;
8163                         sw += 4;
8164                         // modify the vertex
8165                         VectorCopy(vp, tp);
8166                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8167                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8168                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8169                         vp += 3;
8170                         if (vn)
8171                         {
8172                                 // the normal transformation matrix is a set of cross products...
8173                                 CrossProduct(m[1], m[2], n[0]);
8174                                 CrossProduct(m[2], m[0], n[1]);
8175                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8176                                 VectorCopy(vn, tn);
8177                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8178                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8179                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8180                                 VectorNormalize(vn);
8181                                 vn += 3;
8182                                 if (vs)
8183                                 {
8184                                         VectorCopy(vs, ts);
8185                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8186                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8187                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8188                                         VectorNormalize(vs);
8189                                         vs += 3;
8190                                         VectorCopy(vt, tt);
8191                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8192                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8193                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8194                                         VectorNormalize(vt);
8195                                         vt += 3;
8196                                 }
8197                         }
8198                 }
8199                 rsurface.batchskeletaltransform3x4 = NULL;
8200                 rsurface.batchskeletalnumtransforms = 0;
8201         }
8202
8203         // q1bsp surfaces rendered in vertex color mode have to have colors
8204         // calculated based on lightstyles
8205         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8206         {
8207                 // generate color arrays for the surfaces in this list
8208                 int c[4];
8209                 int scale;
8210                 int size3;
8211                 const int *offsets;
8212                 const unsigned char *lm;
8213                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8214                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8215                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8216                 numvertices = 0;
8217                 for (i = 0;i < texturenumsurfaces;i++)
8218                 {
8219                         surface = texturesurfacelist[i];
8220                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8221                         surfacenumvertices = surface->num_vertices;
8222                         if (surface->lightmapinfo->samples)
8223                         {
8224                                 for (j = 0;j < surfacenumvertices;j++)
8225                                 {
8226                                         lm = surface->lightmapinfo->samples + offsets[j];
8227                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8228                                         VectorScale(lm, scale, c);
8229                                         if (surface->lightmapinfo->styles[1] != 255)
8230                                         {
8231                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8232                                                 lm += size3;
8233                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8234                                                 VectorMA(c, scale, lm, c);
8235                                                 if (surface->lightmapinfo->styles[2] != 255)
8236                                                 {
8237                                                         lm += size3;
8238                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8239                                                         VectorMA(c, scale, lm, c);
8240                                                         if (surface->lightmapinfo->styles[3] != 255)
8241                                                         {
8242                                                                 lm += size3;
8243                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8244                                                                 VectorMA(c, scale, lm, c);
8245                                                         }
8246                                                 }
8247                                         }
8248                                         c[0] >>= 7;
8249                                         c[1] >>= 7;
8250                                         c[2] >>= 7;
8251                                         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);
8252                                         numvertices++;
8253                                 }
8254                         }
8255                         else
8256                         {
8257                                 for (j = 0;j < surfacenumvertices;j++)
8258                                 {
8259                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8260                                         numvertices++;
8261                                 }
8262                         }
8263                 }
8264         }
8265
8266         // if vertices are deformed (sprite flares and things in maps, possibly
8267         // water waves, bulges and other deformations), modify the copied vertices
8268         // in place
8269         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8270         {
8271                 float scale;
8272                 switch (deform->deform)
8273                 {
8274                 default:
8275                 case Q3DEFORM_PROJECTIONSHADOW:
8276                 case Q3DEFORM_TEXT0:
8277                 case Q3DEFORM_TEXT1:
8278                 case Q3DEFORM_TEXT2:
8279                 case Q3DEFORM_TEXT3:
8280                 case Q3DEFORM_TEXT4:
8281                 case Q3DEFORM_TEXT5:
8282                 case Q3DEFORM_TEXT6:
8283                 case Q3DEFORM_TEXT7:
8284                 case Q3DEFORM_NONE:
8285                         break;
8286                 case Q3DEFORM_AUTOSPRITE:
8287                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8288                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8289                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8290                         VectorNormalize(newforward);
8291                         VectorNormalize(newright);
8292                         VectorNormalize(newup);
8293 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8294 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8295 //                      rsurface.batchvertex3f_bufferoffset = 0;
8296 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8297 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8298 //                      rsurface.batchsvector3f_bufferoffset = 0;
8299 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8300 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8301 //                      rsurface.batchtvector3f_bufferoffset = 0;
8302 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8303 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8304 //                      rsurface.batchnormal3f_bufferoffset = 0;
8305                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8306                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8307                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8308                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8309                                 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);
8310                         // a single autosprite surface can contain multiple sprites...
8311                         for (j = 0;j < batchnumvertices - 3;j += 4)
8312                         {
8313                                 VectorClear(center);
8314                                 for (i = 0;i < 4;i++)
8315                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8316                                 VectorScale(center, 0.25f, center);
8317                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8318                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8319                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8320                                 for (i = 0;i < 4;i++)
8321                                 {
8322                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8323                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8324                                 }
8325                         }
8326                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8327                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8328                         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);
8329                         break;
8330                 case Q3DEFORM_AUTOSPRITE2:
8331                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8332                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8333                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8334                         VectorNormalize(newforward);
8335                         VectorNormalize(newright);
8336                         VectorNormalize(newup);
8337 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8338 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8339 //                      rsurface.batchvertex3f_bufferoffset = 0;
8340                         {
8341                                 const float *v1, *v2;
8342                                 vec3_t start, end;
8343                                 float f, l;
8344                                 struct
8345                                 {
8346                                         float length2;
8347                                         const float *v1;
8348                                         const float *v2;
8349                                 }
8350                                 shortest[2];
8351                                 memset(shortest, 0, sizeof(shortest));
8352                                 // a single autosprite surface can contain multiple sprites...
8353                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8354                                 {
8355                                         VectorClear(center);
8356                                         for (i = 0;i < 4;i++)
8357                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8358                                         VectorScale(center, 0.25f, center);
8359                                         // find the two shortest edges, then use them to define the
8360                                         // axis vectors for rotating around the central axis
8361                                         for (i = 0;i < 6;i++)
8362                                         {
8363                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8364                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8365                                                 l = VectorDistance2(v1, v2);
8366                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8367                                                 if (v1[2] != v2[2])
8368                                                         l += (1.0f / 1024.0f);
8369                                                 if (shortest[0].length2 > l || i == 0)
8370                                                 {
8371                                                         shortest[1] = shortest[0];
8372                                                         shortest[0].length2 = l;
8373                                                         shortest[0].v1 = v1;
8374                                                         shortest[0].v2 = v2;
8375                                                 }
8376                                                 else if (shortest[1].length2 > l || i == 1)
8377                                                 {
8378                                                         shortest[1].length2 = l;
8379                                                         shortest[1].v1 = v1;
8380                                                         shortest[1].v2 = v2;
8381                                                 }
8382                                         }
8383                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8384                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8385                                         // this calculates the right vector from the shortest edge
8386                                         // and the up vector from the edge midpoints
8387                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8388                                         VectorNormalize(right);
8389                                         VectorSubtract(end, start, up);
8390                                         VectorNormalize(up);
8391                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8392                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8393                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8394                                         VectorNegate(forward, forward);
8395                                         VectorReflect(forward, 0, up, forward);
8396                                         VectorNormalize(forward);
8397                                         CrossProduct(up, forward, newright);
8398                                         VectorNormalize(newright);
8399                                         // rotate the quad around the up axis vector, this is made
8400                                         // especially easy by the fact we know the quad is flat,
8401                                         // so we only have to subtract the center position and
8402                                         // measure distance along the right vector, and then
8403                                         // multiply that by the newright vector and add back the
8404                                         // center position
8405                                         // we also need to subtract the old position to undo the
8406                                         // displacement from the center, which we do with a
8407                                         // DotProduct, the subtraction/addition of center is also
8408                                         // optimized into DotProducts here
8409                                         l = DotProduct(right, center);
8410                                         for (i = 0;i < 4;i++)
8411                                         {
8412                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8413                                                 f = DotProduct(right, v1) - l;
8414                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8415                                         }
8416                                 }
8417                         }
8418                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8419                         {
8420 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8421 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8422 //                              rsurface.batchnormal3f_bufferoffset = 0;
8423                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8424                         }
8425                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8426                         {
8427 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8428 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8429 //                              rsurface.batchsvector3f_bufferoffset = 0;
8430 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8431 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8432 //                              rsurface.batchtvector3f_bufferoffset = 0;
8433                                 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);
8434                         }
8435                         break;
8436                 case Q3DEFORM_NORMAL:
8437                         // deform the normals to make reflections wavey
8438                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8439                         rsurface.batchnormal3f_vertexbuffer = NULL;
8440                         rsurface.batchnormal3f_bufferoffset = 0;
8441                         for (j = 0;j < batchnumvertices;j++)
8442                         {
8443                                 float vertex[3];
8444                                 float *normal = rsurface.batchnormal3f + 3*j;
8445                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8446                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8447                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8448                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8449                                 VectorNormalize(normal);
8450                         }
8451                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8452                         {
8453 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8454 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8455 //                              rsurface.batchsvector3f_bufferoffset = 0;
8456 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8457 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8458 //                              rsurface.batchtvector3f_bufferoffset = 0;
8459                                 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);
8460                         }
8461                         break;
8462                 case Q3DEFORM_WAVE:
8463                         // deform vertex array to make wavey water and flags and such
8464                         waveparms[0] = deform->waveparms[0];
8465                         waveparms[1] = deform->waveparms[1];
8466                         waveparms[2] = deform->waveparms[2];
8467                         waveparms[3] = deform->waveparms[3];
8468                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8469                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8470                         // this is how a divisor of vertex influence on deformation
8471                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8472                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8473 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8474 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8475 //                      rsurface.batchvertex3f_bufferoffset = 0;
8476 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8477 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8478 //                      rsurface.batchnormal3f_bufferoffset = 0;
8479                         for (j = 0;j < batchnumvertices;j++)
8480                         {
8481                                 // if the wavefunc depends on time, evaluate it per-vertex
8482                                 if (waveparms[3])
8483                                 {
8484                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8485                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8486                                 }
8487                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8488                         }
8489                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8490                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8491                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8492                         {
8493 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8494 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8495 //                              rsurface.batchsvector3f_bufferoffset = 0;
8496 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8497 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8498 //                              rsurface.batchtvector3f_bufferoffset = 0;
8499                                 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);
8500                         }
8501                         break;
8502                 case Q3DEFORM_BULGE:
8503                         // deform vertex array to make the surface have moving bulges
8504 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8505 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8506 //                      rsurface.batchvertex3f_bufferoffset = 0;
8507 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8508 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8509 //                      rsurface.batchnormal3f_bufferoffset = 0;
8510                         for (j = 0;j < batchnumvertices;j++)
8511                         {
8512                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8513                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8514                         }
8515                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8516                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8517                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8518                         {
8519 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8520 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8521 //                              rsurface.batchsvector3f_bufferoffset = 0;
8522 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8523 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8524 //                              rsurface.batchtvector3f_bufferoffset = 0;
8525                                 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);
8526                         }
8527                         break;
8528                 case Q3DEFORM_MOVE:
8529                         // deform vertex array
8530                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8531                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8532                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8533                         VectorScale(deform->parms, scale, waveparms);
8534 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8535 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8536 //                      rsurface.batchvertex3f_bufferoffset = 0;
8537                         for (j = 0;j < batchnumvertices;j++)
8538                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8539                         break;
8540                 }
8541         }
8542
8543         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8544         {
8545         // generate texcoords based on the chosen texcoord source
8546                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8547                 {
8548                 default:
8549                 case Q3TCGEN_TEXTURE:
8550                         break;
8551                 case Q3TCGEN_LIGHTMAP:
8552         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8553         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8554         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8555                         if (rsurface.batchtexcoordlightmap2f)
8556                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8557                         break;
8558                 case Q3TCGEN_VECTOR:
8559         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8560         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8561         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8562                         for (j = 0;j < batchnumvertices;j++)
8563                         {
8564                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8565                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8566                         }
8567                         break;
8568                 case Q3TCGEN_ENVIRONMENT:
8569                         // make environment reflections using a spheremap
8570                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8571                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8572                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8573                         for (j = 0;j < batchnumvertices;j++)
8574                         {
8575                                 // identical to Q3A's method, but executed in worldspace so
8576                                 // carried models can be shiny too
8577
8578                                 float viewer[3], d, reflected[3], worldreflected[3];
8579
8580                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8581                                 // VectorNormalize(viewer);
8582
8583                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8584
8585                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8586                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8587                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8588                                 // note: this is proportinal to viewer, so we can normalize later
8589
8590                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8591                                 VectorNormalize(worldreflected);
8592
8593                                 // note: this sphere map only uses world x and z!
8594                                 // so positive and negative y will LOOK THE SAME.
8595                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8596                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8597                         }
8598                         break;
8599                 }
8600                 // the only tcmod that needs software vertex processing is turbulent, so
8601                 // check for it here and apply the changes if needed
8602                 // and we only support that as the first one
8603                 // (handling a mixture of turbulent and other tcmods would be problematic
8604                 //  without punting it entirely to a software path)
8605                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8606                 {
8607                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8608                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8609         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8610         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8611         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8612                         for (j = 0;j < batchnumvertices;j++)
8613                         {
8614                                 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);
8615                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8616                         }
8617                 }
8618         }
8619 }
8620
8621 void RSurf_DrawBatch(void)
8622 {
8623         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8624         // through the pipeline, killing it earlier in the pipeline would have
8625         // per-surface overhead rather than per-batch overhead, so it's best to
8626         // reject it here, before it hits glDraw.
8627         if (rsurface.batchnumtriangles == 0)
8628                 return;
8629 #if 0
8630         // batch debugging code
8631         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8632         {
8633                 int i;
8634                 int j;
8635                 int c;
8636                 const int *e;
8637                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8638                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8639                 {
8640                         c = e[i];
8641                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8642                         {
8643                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8644                                 {
8645                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8646                                                 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);
8647                                         break;
8648                                 }
8649                         }
8650                 }
8651         }
8652 #endif
8653         if (rsurface.batchmultidraw)
8654         {
8655                 // issue multiple draws rather than copying index data
8656                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8657                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8658                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8659                 for (i = 0;i < numsurfaces;)
8660                 {
8661                         // combine consecutive surfaces as one draw
8662                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8663                                 if (surfacelist[j] != surfacelist[k] + 1)
8664                                         break;
8665                         firstvertex = surfacelist[i]->num_firstvertex;
8666                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8667                         firsttriangle = surfacelist[i]->num_firsttriangle;
8668                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8669                         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);
8670                         i = j;
8671                 }
8672         }
8673         else
8674         {
8675                 // there is only one consecutive run of index data (may have been combined)
8676                 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);
8677         }
8678 }
8679
8680 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8681 {
8682         // pick the closest matching water plane
8683         int planeindex, vertexindex, bestplaneindex = -1;
8684         float d, bestd;
8685         vec3_t vert;
8686         const float *v;
8687         r_waterstate_waterplane_t *p;
8688         qboolean prepared = false;
8689         bestd = 0;
8690         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8691         {
8692                 if(p->camera_entity != rsurface.texture->camera_entity)
8693                         continue;
8694                 d = 0;
8695                 if(!prepared)
8696                 {
8697                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8698                         prepared = true;
8699                         if(rsurface.batchnumvertices == 0)
8700                                 break;
8701                 }
8702                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8703                 {
8704                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8705                         d += fabs(PlaneDiff(vert, &p->plane));
8706                 }
8707                 if (bestd > d || bestplaneindex < 0)
8708                 {
8709                         bestd = d;
8710                         bestplaneindex = planeindex;
8711                 }
8712         }
8713         return bestplaneindex;
8714         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8715         // this situation though, as it might be better to render single larger
8716         // batches with useless stuff (backface culled for example) than to
8717         // render multiple smaller batches
8718 }
8719
8720 void RSurf_SetupDepthAndCulling(void)
8721 {
8722         // submodels are biased to avoid z-fighting with world surfaces that they
8723         // may be exactly overlapping (avoids z-fighting artifacts on certain
8724         // doors and things in Quake maps)
8725         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8726         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8727         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8728         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8729 }
8730
8731 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8732 {
8733         int j;
8734         const float *v;
8735         float p[3], mins[3], maxs[3];
8736         int scissor[4];
8737         // transparent sky would be ridiculous
8738         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8739                 return;
8740         R_SetupShader_Generic_NoTexture(false, false);
8741         skyrenderlater = true;
8742         RSurf_SetupDepthAndCulling();
8743         GL_DepthMask(true);
8744
8745         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8746         if (r_sky_scissor.integer)
8747         {
8748                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8749                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8750                 {
8751                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8752                         if (j > 0)
8753                         {
8754                                 if (mins[0] > p[0]) mins[0] = p[0];
8755                                 if (mins[1] > p[1]) mins[1] = p[1];
8756                                 if (mins[2] > p[2]) mins[2] = p[2];
8757                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8758                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8759                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8760                         }
8761                         else
8762                         {
8763                                 VectorCopy(p, mins);
8764                                 VectorCopy(p, maxs);
8765                         }
8766                 }
8767                 if (!R_ScissorForBBox(mins, maxs, scissor))
8768                 {
8769                         if (skyscissor[2])
8770                         {
8771                                 if (skyscissor[0] > scissor[0])
8772                                 {
8773                                         skyscissor[2] += skyscissor[0] - scissor[0];
8774                                         skyscissor[0] = scissor[0];
8775                                 }
8776                                 if (skyscissor[1] > scissor[1])
8777                                 {
8778                                         skyscissor[3] += skyscissor[1] - scissor[1];
8779                                         skyscissor[1] = scissor[1];
8780                                 }
8781                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8782                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8783                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8784                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8785                         }
8786                         else
8787                                 Vector4Copy(scissor, skyscissor);
8788                 }
8789         }
8790
8791         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8792         // skymasking on them, and Quake3 never did sky masking (unlike
8793         // software Quake and software Quake2), so disable the sky masking
8794         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8795         // and skymasking also looks very bad when noclipping outside the
8796         // level, so don't use it then either.
8797         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)
8798         {
8799                 R_Mesh_ResetTextureState();
8800                 if (skyrendermasked)
8801                 {
8802                         R_SetupShader_DepthOrShadow(false, false, false);
8803                         // depth-only (masking)
8804                         GL_ColorMask(0, 0, 0, 0);
8805                         // just to make sure that braindead drivers don't draw
8806                         // anything despite that colormask...
8807                         GL_BlendFunc(GL_ZERO, GL_ONE);
8808                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8809                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8810                 }
8811                 else
8812                 {
8813                         R_SetupShader_Generic_NoTexture(false, false);
8814                         // fog sky
8815                         GL_BlendFunc(GL_ONE, GL_ZERO);
8816                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8817                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8818                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8819                 }
8820                 RSurf_DrawBatch();
8821                 if (skyrendermasked)
8822                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8823         }
8824         R_Mesh_ResetTextureState();
8825         GL_Color(1, 1, 1, 1);
8826 }
8827
8828 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8829 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8830 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8831 {
8832         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8833                 return;
8834         if (prepass)
8835         {
8836                 // render screenspace normalmap to texture
8837                 GL_DepthMask(true);
8838                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
8839                 RSurf_DrawBatch();
8840                 return;
8841         }
8842
8843         // bind lightmap texture
8844
8845         // water/refraction/reflection/camera surfaces have to be handled specially
8846         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8847         {
8848                 int start, end, startplaneindex;
8849                 for (start = 0;start < texturenumsurfaces;start = end)
8850                 {
8851                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8852                         if(startplaneindex < 0)
8853                         {
8854                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8855                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8856                                 end = start + 1;
8857                                 continue;
8858                         }
8859                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8860                                 ;
8861                         // now that we have a batch using the same planeindex, render it
8862                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8863                         {
8864                                 // render water or distortion background
8865                                 GL_DepthMask(true);
8866                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8867                                 RSurf_DrawBatch();
8868                                 // blend surface on top
8869                                 GL_DepthMask(false);
8870                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
8871                                 RSurf_DrawBatch();
8872                         }
8873                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8874                         {
8875                                 // render surface with reflection texture as input
8876                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8877                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
8878                                 RSurf_DrawBatch();
8879                         }
8880                 }
8881                 return;
8882         }
8883
8884         // render surface batch normally
8885         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8886         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui);
8887         RSurf_DrawBatch();
8888 }
8889
8890 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
8891 {
8892         int vi;
8893         int j;
8894         int texturesurfaceindex;
8895         int k;
8896         const msurface_t *surface;
8897         float surfacecolor4f[4];
8898
8899 //      R_Mesh_ResetTextureState();
8900         R_SetupShader_Generic_NoTexture(false, false);
8901
8902         GL_BlendFunc(GL_ONE, GL_ZERO);
8903         GL_DepthMask(writedepth);
8904
8905         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8906         vi = 0;
8907         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8908         {
8909                 surface = texturesurfacelist[texturesurfaceindex];
8910                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8911                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8912                 for (j = 0;j < surface->num_vertices;j++)
8913                 {
8914                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8915                         vi++;
8916                 }
8917         }
8918         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8919         RSurf_DrawBatch();
8920 }
8921
8922 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass, qboolean ui)
8923 {
8924         CHECKGLERROR
8925         RSurf_SetupDepthAndCulling();
8926         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8927         {
8928                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8929                 return;
8930         }
8931         switch (vid.renderpath)
8932         {
8933         case RENDERPATH_GL32:
8934         case RENDERPATH_GLES2:
8935                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8936                 break;
8937         }
8938         CHECKGLERROR
8939 }
8940
8941 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8942 {
8943         int i, j;
8944         int texturenumsurfaces, endsurface;
8945         texture_t *texture;
8946         const msurface_t *surface;
8947         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8948
8949         RSurf_ActiveModelEntity(ent, true, true, false);
8950
8951         if (r_transparentdepthmasking.integer)
8952         {
8953                 qboolean setup = false;
8954                 for (i = 0;i < numsurfaces;i = j)
8955                 {
8956                         j = i + 1;
8957                         surface = rsurface.modelsurfaces + surfacelist[i];
8958                         texture = surface->texture;
8959                         rsurface.texture = R_GetCurrentTexture(texture);
8960                         rsurface.lightmaptexture = NULL;
8961                         rsurface.deluxemaptexture = NULL;
8962                         rsurface.uselightmaptexture = false;
8963                         // scan ahead until we find a different texture
8964                         endsurface = min(i + 1024, numsurfaces);
8965                         texturenumsurfaces = 0;
8966                         texturesurfacelist[texturenumsurfaces++] = surface;
8967                         for (;j < endsurface;j++)
8968                         {
8969                                 surface = rsurface.modelsurfaces + surfacelist[j];
8970                                 if (texture != surface->texture)
8971                                         break;
8972                                 texturesurfacelist[texturenumsurfaces++] = surface;
8973                         }
8974                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8975                                 continue;
8976                         // render the range of surfaces as depth
8977                         if (!setup)
8978                         {
8979                                 setup = true;
8980                                 GL_ColorMask(0,0,0,0);
8981                                 GL_Color(1,1,1,1);
8982                                 GL_DepthTest(true);
8983                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8984                                 GL_DepthMask(true);
8985 //                              R_Mesh_ResetTextureState();
8986                         }
8987                         RSurf_SetupDepthAndCulling();
8988                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8989                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8990                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8991                         RSurf_DrawBatch();
8992                 }
8993                 if (setup)
8994                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8995         }
8996
8997         for (i = 0;i < numsurfaces;i = j)
8998         {
8999                 j = i + 1;
9000                 surface = rsurface.modelsurfaces + surfacelist[i];
9001                 texture = surface->texture;
9002                 rsurface.texture = R_GetCurrentTexture(texture);
9003                 // scan ahead until we find a different texture
9004                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9005                 texturenumsurfaces = 0;
9006                 texturesurfacelist[texturenumsurfaces++] = surface;
9007                         rsurface.lightmaptexture = surface->lightmaptexture;
9008                         rsurface.deluxemaptexture = surface->deluxemaptexture;
9009                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9010                         for (;j < endsurface;j++)
9011                         {
9012                                 surface = rsurface.modelsurfaces + surfacelist[j];
9013                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9014                                         break;
9015                                 texturesurfacelist[texturenumsurfaces++] = surface;
9016                         }
9017                 // render the range of surfaces
9018                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
9019         }
9020         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9021 }
9022
9023 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9024 {
9025         // transparent surfaces get pushed off into the transparent queue
9026         int surfacelistindex;
9027         const msurface_t *surface;
9028         vec3_t tempcenter, center;
9029         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9030         {
9031                 surface = texturesurfacelist[surfacelistindex];
9032                 if (r_transparent_sortsurfacesbynearest.integer)
9033                 {
9034                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9035                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9036                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9037                 }
9038                 else
9039                 {
9040                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9041                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9042                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9043                 }
9044                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9045                 if (rsurface.entity->transparent_offset) // transparent offset
9046                 {
9047                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9048                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9049                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9050                 }
9051                 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);
9052         }
9053 }
9054
9055 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9056 {
9057         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9058                 return;
9059         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9060                 return;
9061         RSurf_SetupDepthAndCulling();
9062         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9063         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9064         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9065         RSurf_DrawBatch();
9066 }
9067
9068 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9069 {
9070         CHECKGLERROR
9071         if (ui)
9072                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9073         else if (depthonly)
9074                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9075         else if (prepass)
9076         {
9077                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9078                         return;
9079                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9080                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9081                 else
9082                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
9083         }
9084         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9085                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9086         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
9087                 return;
9088         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9089         {
9090                 // in the deferred case, transparent surfaces were queued during prepass
9091                 if (!r_shadow_usingdeferredprepass)
9092                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9093         }
9094         else
9095         {
9096                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9097                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
9098         }
9099         CHECKGLERROR
9100 }
9101
9102 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass, qboolean ui)
9103 {
9104         int i, j;
9105         texture_t *texture;
9106         R_FrameData_SetMark();
9107         // break the surface list down into batches by texture and use of lightmapping
9108         for (i = 0;i < numsurfaces;i = j)
9109         {
9110                 j = i + 1;
9111                 // texture is the base texture pointer, rsurface.texture is the
9112                 // current frame/skin the texture is directing us to use (for example
9113                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9114                 // use skin 1 instead)
9115                 texture = surfacelist[i]->texture;
9116                 rsurface.texture = R_GetCurrentTexture(texture);
9117                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9118                 {
9119                         // if this texture is not the kind we want, skip ahead to the next one
9120                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9121                                 ;
9122                         continue;
9123                 }
9124                 if(depthonly || prepass)
9125                 {
9126                         rsurface.lightmaptexture = NULL;
9127                         rsurface.deluxemaptexture = NULL;
9128                         rsurface.uselightmaptexture = false;
9129                         // simply scan ahead until we find a different texture or lightmap state
9130                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9131                                 ;
9132                 }
9133                 else
9134                 {
9135                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9136                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9137                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9138                         // simply scan ahead until we find a different texture or lightmap state
9139                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9140                                 ;
9141                 }
9142                 // render the range of surfaces
9143                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9144         }
9145         R_FrameData_ReturnToMark();
9146 }
9147
9148 float locboxvertex3f[6*4*3] =
9149 {
9150         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9151         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9152         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9153         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9154         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9155         1,0,0, 0,0,0, 0,1,0, 1,1,0
9156 };
9157
9158 unsigned short locboxelements[6*2*3] =
9159 {
9160          0, 1, 2, 0, 2, 3,
9161          4, 5, 6, 4, 6, 7,
9162          8, 9,10, 8,10,11,
9163         12,13,14, 12,14,15,
9164         16,17,18, 16,18,19,
9165         20,21,22, 20,22,23
9166 };
9167
9168 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9169 {
9170         int i, j;
9171         cl_locnode_t *loc = (cl_locnode_t *)ent;
9172         vec3_t mins, size;
9173         float vertex3f[6*4*3];
9174         CHECKGLERROR
9175         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9176         GL_DepthMask(false);
9177         GL_DepthRange(0, 1);
9178         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9179         GL_DepthTest(true);
9180         GL_CullFace(GL_NONE);
9181         R_EntityMatrix(&identitymatrix);
9182
9183 //      R_Mesh_ResetTextureState();
9184
9185         i = surfacelist[0];
9186         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9187                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9188                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9189                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9190
9191         if (VectorCompare(loc->mins, loc->maxs))
9192         {
9193                 VectorSet(size, 2, 2, 2);
9194                 VectorMA(loc->mins, -0.5f, size, mins);
9195         }
9196         else
9197         {
9198                 VectorCopy(loc->mins, mins);
9199                 VectorSubtract(loc->maxs, loc->mins, size);
9200         }
9201
9202         for (i = 0;i < 6*4*3;)
9203                 for (j = 0;j < 3;j++, i++)
9204                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9205
9206         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9207         R_SetupShader_Generic_NoTexture(false, false);
9208         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9209 }
9210
9211 void R_DrawLocs(void)
9212 {
9213         int index;
9214         cl_locnode_t *loc, *nearestloc;
9215         vec3_t center;
9216         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9217         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9218         {
9219                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9220                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9221         }
9222 }
9223
9224 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9225 {
9226         if (decalsystem->decals)
9227                 Mem_Free(decalsystem->decals);
9228         memset(decalsystem, 0, sizeof(*decalsystem));
9229 }
9230
9231 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)
9232 {
9233         tridecal_t *decal;
9234         tridecal_t *decals;
9235         int i;
9236
9237         // expand or initialize the system
9238         if (decalsystem->maxdecals <= decalsystem->numdecals)
9239         {
9240                 decalsystem_t old = *decalsystem;
9241                 qboolean useshortelements;
9242                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9243                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9244                 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)));
9245                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9246                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9247                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9248                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9249                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9250                 if (decalsystem->numdecals)
9251                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9252                 if (old.decals)
9253                         Mem_Free(old.decals);
9254                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9255                         decalsystem->element3i[i] = i;
9256                 if (useshortelements)
9257                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9258                                 decalsystem->element3s[i] = i;
9259         }
9260
9261         // grab a decal and search for another free slot for the next one
9262         decals = decalsystem->decals;
9263         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9264         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9265                 ;
9266         decalsystem->freedecal = i;
9267         if (decalsystem->numdecals <= i)
9268                 decalsystem->numdecals = i + 1;
9269
9270         // initialize the decal
9271         decal->lived = 0;
9272         decal->triangleindex = triangleindex;
9273         decal->surfaceindex = surfaceindex;
9274         decal->decalsequence = decalsequence;
9275         decal->color4f[0][0] = c0[0];
9276         decal->color4f[0][1] = c0[1];
9277         decal->color4f[0][2] = c0[2];
9278         decal->color4f[0][3] = 1;
9279         decal->color4f[1][0] = c1[0];
9280         decal->color4f[1][1] = c1[1];
9281         decal->color4f[1][2] = c1[2];
9282         decal->color4f[1][3] = 1;
9283         decal->color4f[2][0] = c2[0];
9284         decal->color4f[2][1] = c2[1];
9285         decal->color4f[2][2] = c2[2];
9286         decal->color4f[2][3] = 1;
9287         decal->vertex3f[0][0] = v0[0];
9288         decal->vertex3f[0][1] = v0[1];
9289         decal->vertex3f[0][2] = v0[2];
9290         decal->vertex3f[1][0] = v1[0];
9291         decal->vertex3f[1][1] = v1[1];
9292         decal->vertex3f[1][2] = v1[2];
9293         decal->vertex3f[2][0] = v2[0];
9294         decal->vertex3f[2][1] = v2[1];
9295         decal->vertex3f[2][2] = v2[2];
9296         decal->texcoord2f[0][0] = t0[0];
9297         decal->texcoord2f[0][1] = t0[1];
9298         decal->texcoord2f[1][0] = t1[0];
9299         decal->texcoord2f[1][1] = t1[1];
9300         decal->texcoord2f[2][0] = t2[0];
9301         decal->texcoord2f[2][1] = t2[1];
9302         TriangleNormal(v0, v1, v2, decal->plane);
9303         VectorNormalize(decal->plane);
9304         decal->plane[3] = DotProduct(v0, decal->plane);
9305 }
9306
9307 extern cvar_t cl_decals_bias;
9308 extern cvar_t cl_decals_models;
9309 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9310 // baseparms, parms, temps
9311 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)
9312 {
9313         int cornerindex;
9314         int index;
9315         float v[9][3];
9316         const float *vertex3f;
9317         const float *normal3f;
9318         int numpoints;
9319         float points[2][9][3];
9320         float temp[3];
9321         float tc[9][2];
9322         float f;
9323         float c[9][4];
9324         const int *e;
9325
9326         e = rsurface.modelelement3i + 3*triangleindex;
9327
9328         vertex3f = rsurface.modelvertex3f;
9329         normal3f = rsurface.modelnormal3f;
9330
9331         if (normal3f)
9332         {
9333                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9334                 {
9335                         index = 3*e[cornerindex];
9336                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9337                 }
9338         }
9339         else
9340         {
9341                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9342                 {
9343                         index = 3*e[cornerindex];
9344                         VectorCopy(vertex3f + index, v[cornerindex]);
9345                 }
9346         }
9347
9348         // cull backfaces
9349         //TriangleNormal(v[0], v[1], v[2], normal);
9350         //if (DotProduct(normal, localnormal) < 0.0f)
9351         //      continue;
9352         // clip by each of the box planes formed from the projection matrix
9353         // if anything survives, we emit the decal
9354         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]);
9355         if (numpoints < 3)
9356                 return;
9357         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]);
9358         if (numpoints < 3)
9359                 return;
9360         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]);
9361         if (numpoints < 3)
9362                 return;
9363         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]);
9364         if (numpoints < 3)
9365                 return;
9366         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]);
9367         if (numpoints < 3)
9368                 return;
9369         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]);
9370         if (numpoints < 3)
9371                 return;
9372         // some part of the triangle survived, so we have to accept it...
9373         if (dynamic)
9374         {
9375                 // dynamic always uses the original triangle
9376                 numpoints = 3;
9377                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9378                 {
9379                         index = 3*e[cornerindex];
9380                         VectorCopy(vertex3f + index, v[cornerindex]);
9381                 }
9382         }
9383         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9384         {
9385                 // convert vertex positions to texcoords
9386                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9387                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9388                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9389                 // calculate distance fade from the projection origin
9390                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9391                 f = bound(0.0f, f, 1.0f);
9392                 c[cornerindex][0] = r * f;
9393                 c[cornerindex][1] = g * f;
9394                 c[cornerindex][2] = b * f;
9395                 c[cornerindex][3] = 1.0f;
9396                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9397         }
9398         if (dynamic)
9399                 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);
9400         else
9401                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9402                         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);
9403 }
9404 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)
9405 {
9406         matrix4x4_t projection;
9407         decalsystem_t *decalsystem;
9408         qboolean dynamic;
9409         dp_model_t *model;
9410         const msurface_t *surface;
9411         const msurface_t *surfaces;
9412         const int *surfacelist;
9413         const texture_t *texture;
9414         int numtriangles;
9415         int numsurfacelist;
9416         int surfacelistindex;
9417         int surfaceindex;
9418         int triangleindex;
9419         float localorigin[3];
9420         float localnormal[3];
9421         float localmins[3];
9422         float localmaxs[3];
9423         float localsize;
9424         //float normal[3];
9425         float planes[6][4];
9426         float angles[3];
9427         bih_t *bih;
9428         int bih_triangles_count;
9429         int bih_triangles[256];
9430         int bih_surfaces[256];
9431
9432         decalsystem = &ent->decalsystem;
9433         model = ent->model;
9434         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9435         {
9436                 R_DecalSystem_Reset(&ent->decalsystem);
9437                 return;
9438         }
9439
9440         if (!model->brush.data_leafs && !cl_decals_models.integer)
9441         {
9442                 if (decalsystem->model)
9443                         R_DecalSystem_Reset(decalsystem);
9444                 return;
9445         }
9446
9447         if (decalsystem->model != model)
9448                 R_DecalSystem_Reset(decalsystem);
9449         decalsystem->model = model;
9450
9451         RSurf_ActiveModelEntity(ent, true, false, false);
9452
9453         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9454         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9455         VectorNormalize(localnormal);
9456         localsize = worldsize*rsurface.inversematrixscale;
9457         localmins[0] = localorigin[0] - localsize;
9458         localmins[1] = localorigin[1] - localsize;
9459         localmins[2] = localorigin[2] - localsize;
9460         localmaxs[0] = localorigin[0] + localsize;
9461         localmaxs[1] = localorigin[1] + localsize;
9462         localmaxs[2] = localorigin[2] + localsize;
9463
9464         //VectorCopy(localnormal, planes[4]);
9465         //VectorVectors(planes[4], planes[2], planes[0]);
9466         AnglesFromVectors(angles, localnormal, NULL, false);
9467         AngleVectors(angles, planes[0], planes[2], planes[4]);
9468         VectorNegate(planes[0], planes[1]);
9469         VectorNegate(planes[2], planes[3]);
9470         VectorNegate(planes[4], planes[5]);
9471         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9472         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9473         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9474         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9475         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9476         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9477
9478 #if 1
9479 // works
9480 {
9481         matrix4x4_t forwardprojection;
9482         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9483         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9484 }
9485 #else
9486 // broken
9487 {
9488         float projectionvector[4][3];
9489         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9490         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9491         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9492         projectionvector[0][0] = planes[0][0] * ilocalsize;
9493         projectionvector[0][1] = planes[1][0] * ilocalsize;
9494         projectionvector[0][2] = planes[2][0] * ilocalsize;
9495         projectionvector[1][0] = planes[0][1] * ilocalsize;
9496         projectionvector[1][1] = planes[1][1] * ilocalsize;
9497         projectionvector[1][2] = planes[2][1] * ilocalsize;
9498         projectionvector[2][0] = planes[0][2] * ilocalsize;
9499         projectionvector[2][1] = planes[1][2] * ilocalsize;
9500         projectionvector[2][2] = planes[2][2] * ilocalsize;
9501         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9502         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9503         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9504         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9505 }
9506 #endif
9507
9508         dynamic = model->surfmesh.isanimated;
9509         numsurfacelist = model->nummodelsurfaces;
9510         surfacelist = model->sortedmodelsurfaces;
9511         surfaces = model->data_surfaces;
9512
9513         bih = NULL;
9514         bih_triangles_count = -1;
9515         if(!dynamic)
9516         {
9517                 if(model->render_bih.numleafs)
9518                         bih = &model->render_bih;
9519                 else if(model->collision_bih.numleafs)
9520                         bih = &model->collision_bih;
9521         }
9522         if(bih)
9523                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9524         if(bih_triangles_count == 0)
9525                 return;
9526         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9527                 return;
9528         if(bih_triangles_count > 0)
9529         {
9530                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9531                 {
9532                         surfaceindex = bih_surfaces[triangleindex];
9533                         surface = surfaces + surfaceindex;
9534                         texture = surface->texture;
9535                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9536                                 continue;
9537                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9538                                 continue;
9539                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9540                 }
9541         }
9542         else
9543         {
9544                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9545                 {
9546                         surfaceindex = surfacelist[surfacelistindex];
9547                         surface = surfaces + surfaceindex;
9548                         // check cull box first because it rejects more than any other check
9549                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9550                                 continue;
9551                         // skip transparent surfaces
9552                         texture = surface->texture;
9553                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9554                                 continue;
9555                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9556                                 continue;
9557                         numtriangles = surface->num_triangles;
9558                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9559                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9560                 }
9561         }
9562 }
9563
9564 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9565 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)
9566 {
9567         int renderentityindex;
9568         float worldmins[3];
9569         float worldmaxs[3];
9570         entity_render_t *ent;
9571
9572         worldmins[0] = worldorigin[0] - worldsize;
9573         worldmins[1] = worldorigin[1] - worldsize;
9574         worldmins[2] = worldorigin[2] - worldsize;
9575         worldmaxs[0] = worldorigin[0] + worldsize;
9576         worldmaxs[1] = worldorigin[1] + worldsize;
9577         worldmaxs[2] = worldorigin[2] + worldsize;
9578
9579         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9580
9581         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9582         {
9583                 ent = r_refdef.scene.entities[renderentityindex];
9584                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9585                         continue;
9586
9587                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9588         }
9589 }
9590
9591 typedef struct r_decalsystem_splatqueue_s
9592 {
9593         vec3_t worldorigin;
9594         vec3_t worldnormal;
9595         float color[4];
9596         float tcrange[4];
9597         float worldsize;
9598         unsigned int decalsequence;
9599 }
9600 r_decalsystem_splatqueue_t;
9601
9602 int r_decalsystem_numqueued = 0;
9603 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9604
9605 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)
9606 {
9607         r_decalsystem_splatqueue_t *queue;
9608
9609         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9610                 return;
9611
9612         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9613         VectorCopy(worldorigin, queue->worldorigin);
9614         VectorCopy(worldnormal, queue->worldnormal);
9615         Vector4Set(queue->color, r, g, b, a);
9616         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9617         queue->worldsize = worldsize;
9618         queue->decalsequence = cl.decalsequence++;
9619 }
9620
9621 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9622 {
9623         int i;
9624         r_decalsystem_splatqueue_t *queue;
9625
9626         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9627                 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);
9628         r_decalsystem_numqueued = 0;
9629 }
9630
9631 extern cvar_t cl_decals_max;
9632 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9633 {
9634         int i;
9635         decalsystem_t *decalsystem = &ent->decalsystem;
9636         int numdecals;
9637         unsigned int killsequence;
9638         tridecal_t *decal;
9639         float frametime;
9640         float lifetime;
9641
9642         if (!decalsystem->numdecals)
9643                 return;
9644
9645         if (r_showsurfaces.integer)
9646                 return;
9647
9648         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9649         {
9650                 R_DecalSystem_Reset(decalsystem);
9651                 return;
9652         }
9653
9654         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9655         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9656
9657         if (decalsystem->lastupdatetime)
9658                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9659         else
9660                 frametime = 0;
9661         decalsystem->lastupdatetime = r_refdef.scene.time;
9662         numdecals = decalsystem->numdecals;
9663
9664         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9665         {
9666                 if (decal->color4f[0][3])
9667                 {
9668                         decal->lived += frametime;
9669                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9670                         {
9671                                 memset(decal, 0, sizeof(*decal));
9672                                 if (decalsystem->freedecal > i)
9673                                         decalsystem->freedecal = i;
9674                         }
9675                 }
9676         }
9677         decal = decalsystem->decals;
9678         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9679                 numdecals--;
9680
9681         // collapse the array by shuffling the tail decals into the gaps
9682         for (;;)
9683         {
9684                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9685                         decalsystem->freedecal++;
9686                 if (decalsystem->freedecal == numdecals)
9687                         break;
9688                 decal[decalsystem->freedecal] = decal[--numdecals];
9689         }
9690
9691         decalsystem->numdecals = numdecals;
9692
9693         if (numdecals <= 0)
9694         {
9695                 // if there are no decals left, reset decalsystem
9696                 R_DecalSystem_Reset(decalsystem);
9697         }
9698 }
9699
9700 extern skinframe_t *decalskinframe;
9701 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9702 {
9703         int i;
9704         decalsystem_t *decalsystem = &ent->decalsystem;
9705         int numdecals;
9706         tridecal_t *decal;
9707         float faderate;
9708         float alpha;
9709         float *v3f;
9710         float *c4f;
9711         float *t2f;
9712         const int *e;
9713         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9714         int numtris = 0;
9715
9716         numdecals = decalsystem->numdecals;
9717         if (!numdecals)
9718                 return;
9719
9720         if (r_showsurfaces.integer)
9721                 return;
9722
9723         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9724         {
9725                 R_DecalSystem_Reset(decalsystem);
9726                 return;
9727         }
9728
9729         // if the model is static it doesn't matter what value we give for
9730         // wantnormals and wanttangents, so this logic uses only rules applicable
9731         // to a model, knowing that they are meaningless otherwise
9732         RSurf_ActiveModelEntity(ent, false, false, false);
9733
9734         decalsystem->lastupdatetime = r_refdef.scene.time;
9735
9736         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9737
9738         // update vertex positions for animated models
9739         v3f = decalsystem->vertex3f;
9740         c4f = decalsystem->color4f;
9741         t2f = decalsystem->texcoord2f;
9742         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9743         {
9744                 if (!decal->color4f[0][3])
9745                         continue;
9746
9747                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9748                         continue;
9749
9750                 // skip backfaces
9751                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9752                         continue;
9753
9754                 // update color values for fading decals
9755                 if (decal->lived >= cl_decals_time.value)
9756                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9757                 else
9758                         alpha = 1.0f;
9759
9760                 c4f[ 0] = decal->color4f[0][0] * alpha;
9761                 c4f[ 1] = decal->color4f[0][1] * alpha;
9762                 c4f[ 2] = decal->color4f[0][2] * alpha;
9763                 c4f[ 3] = 1;
9764                 c4f[ 4] = decal->color4f[1][0] * alpha;
9765                 c4f[ 5] = decal->color4f[1][1] * alpha;
9766                 c4f[ 6] = decal->color4f[1][2] * alpha;
9767                 c4f[ 7] = 1;
9768                 c4f[ 8] = decal->color4f[2][0] * alpha;
9769                 c4f[ 9] = decal->color4f[2][1] * alpha;
9770                 c4f[10] = decal->color4f[2][2] * alpha;
9771                 c4f[11] = 1;
9772
9773                 t2f[0] = decal->texcoord2f[0][0];
9774                 t2f[1] = decal->texcoord2f[0][1];
9775                 t2f[2] = decal->texcoord2f[1][0];
9776                 t2f[3] = decal->texcoord2f[1][1];
9777                 t2f[4] = decal->texcoord2f[2][0];
9778                 t2f[5] = decal->texcoord2f[2][1];
9779
9780                 // update vertex positions for animated models
9781                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9782                 {
9783                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9784                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9785                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9786                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9787                 }
9788                 else
9789                 {
9790                         VectorCopy(decal->vertex3f[0], v3f);
9791                         VectorCopy(decal->vertex3f[1], v3f + 3);
9792                         VectorCopy(decal->vertex3f[2], v3f + 6);
9793                 }
9794
9795                 if (r_refdef.fogenabled)
9796                 {
9797                         alpha = RSurf_FogVertex(v3f);
9798                         VectorScale(c4f, alpha, c4f);
9799                         alpha = RSurf_FogVertex(v3f + 3);
9800                         VectorScale(c4f + 4, alpha, c4f + 4);
9801                         alpha = RSurf_FogVertex(v3f + 6);
9802                         VectorScale(c4f + 8, alpha, c4f + 8);
9803                 }
9804
9805                 v3f += 9;
9806                 c4f += 12;
9807                 t2f += 6;
9808                 numtris++;
9809         }
9810
9811         if (numtris > 0)
9812         {
9813                 r_refdef.stats[r_stat_drawndecals] += numtris;
9814
9815                 // now render the decals all at once
9816                 // (this assumes they all use one particle font texture!)
9817                 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);
9818 //              R_Mesh_ResetTextureState();
9819                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9820                 GL_DepthMask(false);
9821                 GL_DepthRange(0, 1);
9822                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9823                 GL_DepthTest(true);
9824                 GL_CullFace(GL_NONE);
9825                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9826                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9827                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9828         }
9829 }
9830
9831 static void R_DrawModelDecals(void)
9832 {
9833         int i, numdecals;
9834
9835         // fade faster when there are too many decals
9836         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9837         for (i = 0;i < r_refdef.scene.numentities;i++)
9838                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9839
9840         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9841         for (i = 0;i < r_refdef.scene.numentities;i++)
9842                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9843                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9844
9845         R_DecalSystem_ApplySplatEntitiesQueue();
9846
9847         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9848         for (i = 0;i < r_refdef.scene.numentities;i++)
9849                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9850
9851         r_refdef.stats[r_stat_totaldecals] += numdecals;
9852
9853         if (r_showsurfaces.integer || !r_drawdecals.integer)
9854                 return;
9855
9856         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9857
9858         for (i = 0;i < r_refdef.scene.numentities;i++)
9859         {
9860                 if (!r_refdef.viewcache.entityvisible[i])
9861                         continue;
9862                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9863                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9864         }
9865 }
9866
9867 static void R_DrawDebugModel(void)
9868 {
9869         entity_render_t *ent = rsurface.entity;
9870         int i, j, flagsmask;
9871         const msurface_t *surface;
9872         dp_model_t *model = ent->model;
9873
9874         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9875                 return;
9876
9877         if (r_showoverdraw.value > 0)
9878         {
9879                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9880                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9881                 R_SetupShader_Generic_NoTexture(false, false);
9882                 GL_DepthTest(false);
9883                 GL_DepthMask(false);
9884                 GL_DepthRange(0, 1);
9885                 GL_BlendFunc(GL_ONE, GL_ONE);
9886                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9887                 {
9888                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9889                                 continue;
9890                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9891                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9892                         {
9893                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9894                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9895                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9896                                         GL_Color(c, 0, 0, 1.0f);
9897                                 else if (ent == r_refdef.scene.worldentity)
9898                                         GL_Color(c, c, c, 1.0f);
9899                                 else
9900                                         GL_Color(0, c, 0, 1.0f);
9901                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9902                                 RSurf_DrawBatch();
9903                         }
9904                 }
9905                 rsurface.texture = NULL;
9906         }
9907
9908         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9909
9910 //      R_Mesh_ResetTextureState();
9911         R_SetupShader_Generic_NoTexture(false, false);
9912         GL_DepthRange(0, 1);
9913         GL_DepthTest(!r_showdisabledepthtest.integer);
9914         GL_DepthMask(false);
9915         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9916
9917         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9918         {
9919                 int triangleindex;
9920                 int bihleafindex;
9921                 qboolean cullbox = false;
9922                 const q3mbrush_t *brush;
9923                 const bih_t *bih = &model->collision_bih;
9924                 const bih_leaf_t *bihleaf;
9925                 float vertex3f[3][3];
9926                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9927                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9928                 {
9929                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
9930                                 continue;
9931                         switch (bihleaf->type)
9932                         {
9933                         case BIH_BRUSH:
9934                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9935                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9936                                 {
9937                                         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);
9938                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9939                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9940                                 }
9941                                 break;
9942                         case BIH_COLLISIONTRIANGLE:
9943                                 triangleindex = bihleaf->itemindex;
9944                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9945                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9946                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9947                                 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);
9948                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9949                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9950                                 break;
9951                         case BIH_RENDERTRIANGLE:
9952                                 triangleindex = bihleaf->itemindex;
9953                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9954                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9955                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9956                                 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);
9957                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9958                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9959                                 break;
9960                         }
9961                 }
9962         }
9963
9964         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9965
9966 #ifndef USE_GLES2
9967         if (r_showtris.value > 0 && qglPolygonMode)
9968         {
9969                 if (r_showdisabledepthtest.integer)
9970                 {
9971                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9972                         GL_DepthMask(false);
9973                 }
9974                 else
9975                 {
9976                         GL_BlendFunc(GL_ONE, GL_ZERO);
9977                         GL_DepthMask(true);
9978                 }
9979                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9980                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
9981                 {
9982                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9983                                 continue;
9984                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9985                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9986                         {
9987                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9988                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9989                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9990                                 else if (ent == r_refdef.scene.worldentity)
9991                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9992                                 else
9993                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9994                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9995                                 RSurf_DrawBatch();
9996                         }
9997                 }
9998                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9999                 rsurface.texture = NULL;
10000         }
10001
10002 # if 0
10003         // FIXME!  implement r_shownormals with just triangles
10004         if (r_shownormals.value != 0 && qglBegin)
10005         {
10006                 int l, k;
10007                 vec3_t v;
10008                 if (r_showdisabledepthtest.integer)
10009                 {
10010                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10011                         GL_DepthMask(false);
10012                 }
10013                 else
10014                 {
10015                         GL_BlendFunc(GL_ONE, GL_ZERO);
10016                         GL_DepthMask(true);
10017                 }
10018                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10019                 {
10020                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10021                                 continue;
10022                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10023                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10024                         {
10025                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10026                                 qglBegin(GL_LINES);
10027                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10028                                 {
10029                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10030                                         {
10031                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10032                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10033                                                 qglVertex3f(v[0], v[1], v[2]);
10034                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10035                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10036                                                 qglVertex3f(v[0], v[1], v[2]);
10037                                         }
10038                                 }
10039                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10040                                 {
10041                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10042                                         {
10043                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10044                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10045                                                 qglVertex3f(v[0], v[1], v[2]);
10046                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10047                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10048                                                 qglVertex3f(v[0], v[1], v[2]);
10049                                         }
10050                                 }
10051                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10052                                 {
10053                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10054                                         {
10055                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10056                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10057                                                 qglVertex3f(v[0], v[1], v[2]);
10058                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10059                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10060                                                 qglVertex3f(v[0], v[1], v[2]);
10061                                         }
10062                                 }
10063                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10064                                 {
10065                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10066                                         {
10067                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10068                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10069                                                 qglVertex3f(v[0], v[1], v[2]);
10070                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10071                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10072                                                 qglVertex3f(v[0], v[1], v[2]);
10073                                         }
10074                                 }
10075                                 qglEnd();
10076                                 CHECKGLERROR
10077                         }
10078                 }
10079                 rsurface.texture = NULL;
10080         }
10081 # endif
10082 #endif
10083 }
10084
10085 int r_maxsurfacelist = 0;
10086 const msurface_t **r_surfacelist = NULL;
10087 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass, qboolean ui)
10088 {
10089         int i, j, endj, flagsmask;
10090         dp_model_t *model = ent->model;
10091         msurface_t *surfaces;
10092         unsigned char *update;
10093         int numsurfacelist = 0;
10094         if (model == NULL)
10095                 return;
10096
10097         if (r_maxsurfacelist < model->num_surfaces)
10098         {
10099                 r_maxsurfacelist = model->num_surfaces;
10100                 if (r_surfacelist)
10101                         Mem_Free((msurface_t **)r_surfacelist);
10102                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10103         }
10104
10105         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10106                 RSurf_ActiveModelEntity(ent, false, false, false);
10107         else if (prepass)
10108                 RSurf_ActiveModelEntity(ent, true, true, true);
10109         else if (depthonly)
10110                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10111         else
10112                 RSurf_ActiveModelEntity(ent, true, true, false);
10113
10114         surfaces = model->data_surfaces;
10115         update = model->brushq1.lightmapupdateflags;
10116
10117         // update light styles
10118         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10119         {
10120                 model_brush_lightstyleinfo_t *style;
10121                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10122                 {
10123                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10124                         {
10125                                 int *list = style->surfacelist;
10126                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10127                                 for (j = 0;j < style->numsurfaces;j++)
10128                                         update[list[j]] = true;
10129                         }
10130                 }
10131         }
10132
10133         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10134
10135         if (debug)
10136         {
10137                 R_DrawDebugModel();
10138                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10139                 return;
10140         }
10141
10142         rsurface.lightmaptexture = NULL;
10143         rsurface.deluxemaptexture = NULL;
10144         rsurface.uselightmaptexture = false;
10145         rsurface.texture = NULL;
10146         rsurface.rtlight = NULL;
10147         numsurfacelist = 0;
10148         // add visible surfaces to draw list
10149         if (ent == r_refdef.scene.worldentity)
10150         {
10151                 // for the world entity, check surfacevisible
10152                 for (i = 0;i < model->nummodelsurfaces;i++)
10153                 {
10154                         j = model->sortedmodelsurfaces[i];
10155                         if (r_refdef.viewcache.world_surfacevisible[j])
10156                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10157                 }
10158         }
10159         else if (ui)
10160         {
10161                 // for ui we have to preserve the order of surfaces
10162                 for (i = 0; i < model->nummodelsurfaces; i++)
10163                         r_surfacelist[numsurfacelist++] = surfaces + model->firstmodelsurface + i;
10164         }
10165         else
10166         {
10167                 // add all surfaces
10168                 for (i = 0; i < model->nummodelsurfaces; i++)
10169                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10170         }
10171         // don't do anything if there were no surfaces
10172         if (!numsurfacelist)
10173         {
10174                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10175                 return;
10176         }
10177         // update lightmaps if needed
10178         if (update)
10179         {
10180                 int updated = 0;
10181                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10182                 {
10183                         if (update[j])
10184                         {
10185                                 updated++;
10186                                 R_BuildLightMap(ent, surfaces + j);
10187                         }
10188                 }
10189         }
10190
10191         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10192
10193         // add to stats if desired
10194         if (r_speeds.integer && !skysurfaces && !depthonly)
10195         {
10196                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10197                 for (j = 0;j < numsurfacelist;j++)
10198                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10199         }
10200
10201         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10202 }
10203
10204 void R_DebugLine(vec3_t start, vec3_t end)
10205 {
10206         dp_model_t *mod = CL_Mesh_UI();
10207         msurface_t *surf;
10208         int e0, e1, e2, e3;
10209         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10210         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10211         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10212         vec4_t w[2], s[2];
10213
10214         // transform to screen coords first
10215         Vector4Set(w[0], start[0], start[1], start[2], 1);
10216         Vector4Set(w[1], end[0], end[1], end[2], 1);
10217         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10218         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10219         x1 = s[0][0] * vid_conwidth.value / vid.width;
10220         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10221         x2 = s[1][0] * vid_conwidth.value / vid.width;
10222         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10223         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10224
10225         // add the line to the UI mesh for drawing later
10226
10227         // width is measured in real pixels
10228         if (fabs(x2 - x1) > fabs(y2 - y1))
10229         {
10230                 offsetx = 0;
10231                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10232         }
10233         else
10234         {
10235                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10236                 offsety = 0;
10237         }
10238         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);
10239         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10240         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10241         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10242         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10243         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10244         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10245
10246 }
10247
10248
10249 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)
10250 {
10251         static texture_t texture;
10252
10253         // fake enough texture and surface state to render this geometry
10254
10255         texture.update_lastrenderframe = -1; // regenerate this texture
10256         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10257         texture.basealpha = 1.0f;
10258         texture.currentskinframe = skinframe;
10259         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10260         texture.offsetmapping = OFFSETMAPPING_OFF;
10261         texture.offsetscale = 1;
10262         texture.specularscalemod = 1;
10263         texture.specularpowermod = 1;
10264         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10265
10266         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10267 }
10268
10269 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)
10270 {
10271         static msurface_t surface;
10272         const msurface_t *surfacelist = &surface;
10273
10274         // fake enough texture and surface state to render this geometry
10275         surface.texture = texture;
10276         surface.num_triangles = numtriangles;
10277         surface.num_firsttriangle = firsttriangle;
10278         surface.num_vertices = numvertices;
10279         surface.num_firstvertex = firstvertex;
10280
10281         // now render it
10282         rsurface.texture = R_GetCurrentTexture(surface.texture);
10283         rsurface.lightmaptexture = NULL;
10284         rsurface.deluxemaptexture = NULL;
10285         rsurface.uselightmaptexture = false;
10286         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10287 }